Facebook.Unity/Codeless/CodelessCrawler.cs (197 lines of code) (raw):

/** * Copyright (c) 2014-present, Facebook, Inc. All rights reserved. * * You are hereby granted a non-exclusive, worldwide, royalty-free license to use, * copy, modify, and distribute this software in source code or binary form for use * in connection with the web services and APIs provided by Facebook. * * As with any software that integrates with the Facebook platform, your use of * this software is subject to the Facebook Developer Principles and Policies * [http://developers.facebook.com/policy/]. This copyright notice shall be * included in all copies or substantial portions of the software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.UI; using System.IO; using System; using System.Text; using UnityEngine.SceneManagement; using System.Runtime.InteropServices; namespace Facebook.Unity { public class CodelessCrawler : MonoBehaviour { #if UNITY_IOS [DllImport ("__Internal")] private static extern void IOSFBSendViewHierarchy (string tree); #endif private static bool isGeneratingSnapshot = false; private static Camera mainCamera = null; public void Awake () { SceneManager.activeSceneChanged += onActiveSceneChanged; } public void CaptureViewHierarchy (string message) { if (null == mainCamera || !mainCamera.isActiveAndEnabled) { updateMainCamera (); } StartCoroutine (GenSnapshot ()); } private IEnumerator GenSnapshot () { yield return (new WaitForEndOfFrame ()); if (isGeneratingSnapshot) { yield break; } isGeneratingSnapshot = true; StringBuilder masterBuilder = new StringBuilder (); masterBuilder.AppendFormat ( @"{{""screenshot"":""{0}"",", GenBase64Screenshot () ); masterBuilder.AppendFormat ( @"""screenname"":""{0}"",", SceneManager.GetActiveScene ().name ); masterBuilder.AppendFormat ( @"""view"":[{0}]}}", GenViewJson () ); string json = masterBuilder.ToString (); switch (Constants.CurrentPlatform) { case FacebookUnityPlatform.Android: SendAndroid (json); break; case FacebookUnityPlatform.IOS: SendIos (json); break; default: break; } isGeneratingSnapshot = false; } private static void SendAndroid (string json) { using (AndroidJavaObject viewIndexer = new AndroidJavaClass ("com.facebook.appevents.codeless.ViewIndexer")) { viewIndexer.CallStatic ("sendToServerUnityInstance", json); } } private static void SendIos (string json) { #if UNITY_IOS CodelessCrawler.IOSFBSendViewHierarchy (json); #endif } private static string GenBase64Screenshot () { Texture2D tex = new Texture2D (Screen.width, Screen.height); tex.ReadPixels (new Rect (0, 0, Screen.width, Screen.height), 0, 0); tex.Apply (); string screenshot64 = System.Convert.ToBase64String (tex.EncodeToJPG ()); UnityEngine.Object.Destroy (tex); return screenshot64; } private static string GenViewJson () { GameObject[] rootGameObjs = UnityEngine.SceneManagement.SceneManager.GetActiveScene ().GetRootGameObjects (); StringBuilder builder = new StringBuilder (); builder.AppendFormat ( @"{{""classname"":""{0}"",""childviews"":[", SceneManager.GetActiveScene ().name ); foreach (GameObject curObj in rootGameObjs) { GenChild (curObj, builder); builder.Append (","); } if (builder [builder.Length - 1] == ',') { builder.Length--; } builder.AppendFormat ( @"],""classtypebitmask"":""{0}"",""tag"":""0"",""dimension"":{{""height"":{1},""width"":{2},""scrolly"":{3},""left"":{4},""top"":{5},""scrollx"":{6},""visibility"":{7}}}}}", "0", (int)Screen.height, (int)Screen.width, "0", "0", "0", "0", "0" ); return builder.ToString (); } private static void GenChild (GameObject curObj, StringBuilder builder) { builder.AppendFormat ( @"{{""classname"":""{0}"",""childviews"":[", curObj.name ); int childCount = curObj.transform.childCount; for (int i = 0; i < childCount; i++) { if (null == curObj.GetComponent<Button> ()) { GenChild (curObj.transform.GetChild (i).gameObject, builder); builder.Append (","); } } if (builder [builder.Length - 1] == ',') { builder.Length--; } UnityEngine.Canvas canvasParent = curObj.GetComponentInParent<UnityEngine.Canvas> (); string btntext = ""; if (null != curObj.GetComponent<Button> () && null != canvasParent) { Rect rect = curObj.GetComponent<RectTransform> ().rect; Vector2 position = getScreenCoordinate (curObj.transform.position, canvasParent.renderMode); Text textComponent = curObj.GetComponent<Button> ().GetComponentInChildren<Text> (); if (null != textComponent) { btntext = "\"text\":\"" + textComponent.text + "\","; } builder.AppendFormat ( @"],{8}""classtypebitmask"":""{0}"",""tag"":""0"",""dimension"":{{""height"":{1},""width"":{2},""scrolly"":{3},""left"":{4},""top"":{5},""scrollx"":{6},""visibility"":{7}}}}}", getClasstypeBitmaskButton (), (int)rect.height, (int)rect.width, 0, (int)Math.Ceiling (position.x - (rect.width / 2)),//left (int)Math.Ceiling ((Screen.height - position.y - (rect.height / 2))), 0, getVisibility (curObj), btntext ); } else { builder.AppendFormat ( @"],{8}""classtypebitmask"":""{0}"",""tag"":""0"",""dimension"":{{""height"":{1},""width"":{2},""scrolly"":{3},""left"":{4},""top"":{5},""scrollx"":{6},""visibility"":{7}}}}}", getClasstypeBitmaskButton (), 0, 0, 0, 0, 0, 0, getVisibility (curObj), btntext ); } } private void onActiveSceneChanged (Scene arg0, Scene arg1) { updateMainCamera (); } private static void updateMainCamera () { mainCamera = Camera.main; } private static Vector2 getScreenCoordinate (Vector3 position, RenderMode renderMode) { if (RenderMode.ScreenSpaceOverlay == renderMode || null == mainCamera) { return(position); } else { return mainCamera.WorldToScreenPoint (position); } } private static string getClasstypeBitmaskButton () { switch (Constants.CurrentPlatform) { case FacebookUnityPlatform.Android: return "4"; case FacebookUnityPlatform.IOS: return "16"; default: return "0"; } } private static string getVisibility (GameObject gameObj) { if (gameObj.activeInHierarchy) { return "0"; } else { return "8"; } } } }