// Created by ZhuCong on 1/1/14. // Copyright 2014 Umeng.com . All rights reserved. using UnityEngine; using System; using System.Runtime.InteropServices; using System.Collections; using System.Collections.Generic; using System.Text; namespace Umeng { public class Analytics { static string version = "2.3"; #if UNITY_ANDROID static bool hasInit = false; #endif // /// /// 开始友盟统计 默认发送策略为启动时发送 /// /// 友盟appKey /// 渠道名称 public static void StartWithAppKeyAndChannelId(string appKey, string channelId) { #if UNITY_EDITOR //Debug.LogWarning("友盟统计在iOS/Android 真机上才会向友盟后台服务器发送事件 请在真机上测试"); #elif UNITY_IPHONE StartWithAppKeyAndReportPolicyAndChannelId(appKey, ReportPolicy.BATCH, channelId); #elif UNITY_ANDROID _AppKey = appKey; _ChannelId = channelId; UMGameAgentInit(); if(!hasInit) { //Debug.LogWarning("onResume"); onResume(); CreateUmengManger(); hasInit = true; } // EnableActivityDurationTrack(false); #endif } /// /// 设置是否打印sdk的信息,默认不开启 /// /// 设置为true,Umeng SDK 会输出日志信息,记得release产品时要设置回false. /// public static void SetLogEnabled(bool value) { #if UNITY_EDITOR //Debug.Log("SetLogEnabled"); #elif UNITY_IPHONE _SetLogEnabled(value); #elif UNITY_ANDROID Agent.CallStatic("setDebugMode", value); #endif } //使用前,请先到友盟App管理后台的设置->编辑自定义事件 中添加相应的事件ID,然后在工程中传入相应的事件ID //eventId、attributes中key和value都不能使用空格和特殊字符,且长度不能超过255个字符(否则将截取前255个字符) //id, ts, du是保留字段,不能作为eventId及key的名称 /// /// 基本事件 /// /// 友盟后台设定的事件Id public static void Event(string eventId) { #if UNITY_EDITOR //Debug.Log("Event"); #elif UNITY_IPHONE _Event(eventId); #elif UNITY_ANDROID Agent.CallStatic("onEvent", Context, eventId); #endif } //不同的标签会分别进行统计,方便同一事件的不同标签的对比,为nil或空字符串时后台会生成和eventId同名的标签. /// /// 基本事件 /// /// 友盟后台设定的事件Id /// 分类标签 public static void Event(string eventId, string label) { #if UNITY_EDITOR //Debug.Log("Event"); #elif UNITY_IPHONE _EventWithLabel(eventId, label); #elif UNITY_ANDROID Agent.CallStatic("onEvent", Context, eventId, label); #endif } /// /// 属性事件 /// /// 友盟后台设定的事件Id /// 属性中的Key-Vaule Pair不能超过10个 public static void Event(string eventId, Dictionary attributes) { #if UNITY_EDITOR //Debug.Log("Event"); #elif UNITY_IPHONE _EventWithAttributes(eventId, DictionaryToJson(attributes)); #elif UNITY_ANDROID Agent.CallStatic("onEvent", Context, eventId, ToJavaHashMap(attributes)); #endif } /// /// 页面时长统计,记录某个页面被打开多长时间 /// 与PageEnd配对使用 /// /// 被统计view名称 public static void PageBegin(string pageName) { #if UNITY_EDITOR //Debug.Log("PageBegin"); #elif UNITY_IPHONE _BeginLogPageView(pageName); #elif UNITY_ANDROID Agent.CallStatic("onPageStart", pageName); #endif } /// /// 页面时长统计,记录某个页面被打开多长时间 /// 与PageBegin配对使用 /// /// 被统计view名称 /// public static void PageEnd(string pageName) { #if UNITY_EDITOR //Debug.Log("PageEnd"); #elif UNITY_IPHONE _EndLogPageView(pageName); #elif UNITY_ANDROID Agent.CallStatic("onPageEnd", pageName); #endif } /// /// 自定义事件 — 计算事件数 /// public static void Event(string eventId, Dictionary attributes, int value) { try { if (attributes == null) attributes = new System.Collections.Generic.Dictionary(); if (attributes.ContainsKey("__ct__")) { attributes["__ct__"] = value.ToString(); Event(eventId, attributes); } else { attributes.Add("__ct__", value.ToString()); Event(eventId, attributes); attributes.Remove("__ct__"); } } catch (Exception) { } } /// /// 获取缓存的在线参数 /// /// 在线参数的Key 请在友盟后台设置 /// Key对应的在线参数值 public static string GetDeviceInfo() { #if UNITY_EDITOR //Unity Editor 模式下 返回null 请在iOS/Anroid真机上测试 //Debug.Log("GetDeviceInfo return null"); return null; #elif UNITY_IPHONE return _GetDeviceID(); #elif UNITY_ANDROID var util = new AndroidJavaClass("com.umeng.analytics.UnityUtil"); var info = util.CallStatic("getDeviceInfo", Context); return info; #else return null; #endif } //设置是否对日志信息进行加密, 默认false(不加密). //value 设置为true, SDK会将日志信息做加密处理 public static void SetLogEncryptEnabled(bool value) { #if UNITY_EDITOR //Debug.Log("SetLogEncryptEnabled"); #elif UNITY_IPHONE _SetEncryptEnabled(value); #elif UNITY_ANDROID Agent.CallStatic("enableEncrypt", value); #endif } public static void SetLatency(int value) { #if UNITY_EDITOR //Debug.Log("SetLatency"); #elif UNITY_IPHONE //_SetLatency(value); #elif UNITY_ANDROID Agent.CallStatic("setLatencyWindow", (long)value); #endif } public static void Event(string[] keyPath,int value,string label) { #if UNITY_EDITOR #elif UNITY_IPHONE var listStr = String.Join(";=umengUnity=;", keyPath); _CCEvent(listStr,value,label); #elif UNITY_ANDROID var listStr = String.Join(";=umengUnity=;", keyPath); var util = new AndroidJavaClass("com.umeng.analytics.UnityUtil"); util.CallStatic("onEventForUnity", Context, listStr,value,label); #endif } //Android Only #if UNITY_ANDROID //设置Session时长 public static void SetContinueSessionMillis(long milliseconds) { #if UNITY_EDITOR //Debug.Log("setContinueSessionMillis"); #else Agent.CallStatic("setSessionContinueMillis", milliseconds); #endif } [Obsolete("Flush")] //清空缓存 public static void Flush() { #if UNITY_EDITOR //Debug.Log("flush"); #else Agent.CallStatic("flush", Context); #endif } [Obsolete("SetEnableLocation已弃用")] //启用位置信息 public static void SetEnableLocation(bool reportLocation) { #if UNITY_EDITOR //Debug.Log("setEnableLocation:"+ reportLocation); #else Agent.CallStatic("setAutoLocation", reportLocation); #endif } //启用页面统计 public static void EnableActivityDurationTrack(bool isTraceActivity) { #if UNITY_EDITOR //Debug.Log("enableActivityDurationTrack:"+isTraceActivity); #else Agent.CallStatic("openActivityDurationTrack", isTraceActivity); #endif } /* android6.0中采集mac方式变更,新增接口 public static void setCheckDevice(boolean enable) 该接口默认参数是true,即采集mac地址, 但如果开发者需要在googleplay发布,考虑到审核风险,可以调用该接口,参数设置为 false 就不会采集mac地址。 */ public static void SetCheckDevice(bool value) { #if UNITY_EDITOR #else Agent.CallStatic("setCheckDevice", value); #endif } #endif //iOS Only #if UNITY_IPHONE /* BATCH(启动发送)为默认发送策略 关于发送策略的调整,请参见关于发送策略及发送策略变更的说明 http://blog.umeng.com/index.php/2012/12/0601/ SEND_INTERVAL 为按最小间隔发送,默认为10秒,取值范围为10 到 86400(一天), 如果不在这个区间的话,会按10设置。 SEND_ON_EXIT 为退出或进入后台时发送,这种发送策略在App运行过程中不发送,对开发者和用户的影响最小。 不过这种发送策略只在iOS > 4.0时才会生效, iOS < 4.0 会被自动调整为BATCH。 */ public enum ReportPolicy { BATCH = 1,//启动发送 SENDDAILY = 4, //每日发送 SEND_INTERVAL = 6, //按最小间隔发送 SEND_ON_EXIT = 7 //退出或进入后台时发送 } /// /// 开启友盟统计 /// /// 友盟appKey /// 发送策略 /// 渠道名称 /// public static void StartWithAppKeyAndReportPolicyAndChannelId(string appkey, ReportPolicy policy, string channelId) { #if UNITY_EDITOR //Debug.LogWarning("友盟统计在iOS/Androi 真机上才会向友盟后台服务器发送事件 请在真机上测试"); #else _StartWithAppKeyAndReportPolicyAndChannelId(appkey, (int)policy, channelId,version); _AppKey = appkey; _ChannelId = channelId; #endif } /// /// 当reportPolicy 为 SEND_INTERVAL 时设定log发送间隔 /// /// 单位为秒,最小为10,最大为86400(一天). public static void SetLogSendInterval(int seconds) { #if UNITY_EDITOR //Debug.Log("SetLogSendInterval"); #else _SetLogSendInterval((double)seconds); #endif } /// /// 手动设置app版本号 此API不再建议使用 因为启动时会自动读取Unity的Pla yerSettings.bundleVersion(CFBundleVersion)作为版本 /// /// 版本号 [Obsolete("此API不再建议使用 因为启动时会自动读取Unity的PlayerSettings.bundleVersion(CFBundleVersion)作为版本")] public static void SetAppVersion(string value) { #if UNITY_EDITOR //Debug.Log("SetAppVersion"); #else _SetAppVersion(value); #endif } /// /// 开启CrashReport收集, 默认是开启状态. /// /// 设置成false,就可以关闭友盟CrashReport收集 public static void SetCrashReportEnabled(bool value) { #if UNITY_EDITOR //Debug.Log("SetCrashReportEnabled"); #else //由于Unity在iOS平台使用AOT模式编译 你得到的CrashReport函数名将不是完全一致 _SetCrashReportEnabled(value); //Anddroid 平台Crash Report 总是是开启的 无需调用SetCrashReportEnabled //Anddroid 平台Crash Report 仅限于Java层的崩溃日志 #endif } /// /// 页面时长统计,记录某个view被打开多长时间,与调用PageBegin,PageEnd计时等价 /// /// 被统计view名称 /// 时长单位为秒 /// public static void LogPageViewWithSeconds(string pageName, int seconds) { #if UNITY_EDITOR //Debug.Log("LogPageViewWithSeconds"); #else _LogPageViewWithSeconds(pageName, seconds); #endif } /// /// 判断设备是否越狱,判断方法根据 apt和Cydia.app的path来判断 /// /// 是否越狱 public static bool IsJailBroken() { #if UNITY_EDITOR //always return false in UNITY_EDITOR mode //Debug.Log("IsJailBroken always return false in UNITY_EDITOR mode"); return false; #else return _IsJailBroken(); #endif } /// /// 判断你的App是否被破解 /// /// 是否破解 public static bool IsPirated() { #if UNITY_EDITOR //always return false in UNITY_EDITOR mode //Debug.Log("IsPirated always return false in UNITY_EDITOR mode"); return false; #else return _IsPirated(); #endif } //设置是否开启background模式, 默认true. //value 为YES,SDK会确保在app进入后台的短暂时间保存日志信息的完整性,对于已支持background模式和一般app不会有影响. //如果该模式影响某些App在切换到后台的功能,也可将该值设置为false. public static void SetBackgroundTaskEnabled(bool value) { #if UNITY_EDITOR //Debug.Log("SetBackgroundTaskEnabled"); #elif UNITY_IPHONE _SetBackgroundTaskEnabled (value); #endif } #endif #region Wrapper static private string _AppKey=null; static private string _ChannelId=null; static public string AppKey { get { return _AppKey; } } static public string ChannelId { get { return _ChannelId; } } static private void CreateUmengManger() { GameObject go = new GameObject(); go.AddComponent(); go.name = "UmengManager"; } #if UNITY_ANDROID public static void onResume() { #if UNITY_EDITOR #else Agent.CallStatic("onResume", Context); #endif } public static void onPause() { #if UNITY_EDITOR #else Agent.CallStatic("onPause", Context); #endif } public static void onKillProcess() { #if UNITY_EDITOR #else Agent.CallStatic("onKillProcess", Context); #endif } //static AndroidJavaClass AnalyticsConfig = null; //lazy initialize singleton static class SingletonHolder { public static AndroidJavaClass instance_mobclick; public static AndroidJavaObject instance_context; static SingletonHolder() { //instance_mobclick will be null if you run in editor mode //try it on real android device instance_mobclick = new AndroidJavaClass("com.umeng.analytics.game.UMGameAgent"); //AnalyticsConfig = new AndroidJavaClass("com.umeng.analytics.AnalyticsConfig"); //cls_UnityPlayer and instance_context will be null if you run in editor mode //try it on real android device using (AndroidJavaClass cls_UnityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer")) { instance_context = cls_UnityPlayer.GetStatic("currentActivity"); } } } private static AndroidJavaObject ToJavaHashMap(Dictionary dic) { var hashMap = new AndroidJavaObject("java.util.HashMap"); var putMethod = AndroidJNIHelper.GetMethodID(hashMap.GetRawClass(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); var arguments = new object[2]; foreach (var entry in dic) { using (var key = new AndroidJavaObject("java.lang.String", entry.Key)) { using (var val = new AndroidJavaObject("java.lang.String", entry.Value)) { arguments[0] = key; arguments[1] = val; AndroidJNI.CallObjectMethod(hashMap.GetRawObject(), putMethod, AndroidJNIHelper.CreateJNIArgArray(arguments)); } } // end using } // end foreach return hashMap; } protected static AndroidJavaClass Agent { get { //instance_mobclick will be null if you run in editor mode //try it on real android device return SingletonHolder.instance_mobclick; } } static AndroidJavaClass _UpdateAgent; protected static AndroidJavaClass UpdateAgent { get { if (_UpdateAgent == null) _UpdateAgent = new AndroidJavaClass("com.umeng.update.UmengUpdateAgent"); return _UpdateAgent; } } protected static AndroidJavaObject Context { get { //instance_mobclick will be null if you run in editor mode //try it on real android device return SingletonHolder.instance_context; } } public static void UMGameAgentInit() { var util = new AndroidJavaClass("com.umeng.analytics.UnityUtil"); util.CallStatic("initUnity", Context,AppKey,ChannelId,version); } public void Dispose() { Agent.Dispose(); Context.Dispose(); } #endif #if UNITY_IPHONE static string DictionaryToJson(Dictionary dict) { var builder = new StringBuilder("{"); foreach (KeyValuePair kv in dict) { builder.AppendFormat("\"{0}\":\"{1}\",", kv.Key, kv.Value); } builder[builder.Length - 1] = '}'; return builder.ToString(); } [DllImport("__Internal")] private static extern void _SetAppVersion(string value); [DllImport("__Internal")] private static extern void _SetLogEnabled(bool value); [DllImport("__Internal")] private static extern void _SetCrashReportEnabled(bool value); [DllImport("__Internal")] private static extern void _StartWithAppKeyAndReportPolicyAndChannelId(string appkey, int policy, string channelId,string version); [DllImport("__Internal")] private static extern void _SetLogSendInterval(double interval); [DllImport("__Internal")] private static extern void _Event(string eventId); [DllImport("__Internal")] private static extern void _EventWithDuration(string eventId, int duration); [DllImport("__Internal")] private static extern void _EventWithDuration2(string eventId, string Label, int duration); [DllImport("__Internal")] private static extern void _EventWithAttributesAndDuration(string eventId, string jsonString, int duration); [DllImport("__Internal")] private static extern void _EventWithLabel(string eventId, string label); [DllImport("__Internal")] private static extern void _EventWithAccumulation(string eventId, int accumulation); [DllImport("__Internal")] private static extern void _EventWithLabelAndAccumulation(string eventId, string label, int accumulation); [DllImport("__Internal")] private static extern void _EventWithAttributes(string eventId, string jsonstring); [DllImport("__Internal")] private static extern void _BeginEventWithLabel(string eventId, string label); [DllImport("__Internal")] private static extern void _EndEventWithLabel(string eventId, string label); [DllImport("__Internal")] private static extern void _BeginEventWithPrimarykeyAndAttributes(string eventId, string primaryKey, string jsonstring); [DllImport("__Internal")] private static extern void _EndEventWithPrimarykey(string eventId, string primaryKey); [DllImport("__Internal")] private static extern void _LogPageViewWithSeconds(string pageName, int seconds); [DllImport("__Internal")] private static extern void _BeginLogPageView(string pageName); [DllImport("__Internal")] private static extern void _EndLogPageView(string pageName); [DllImport("__Internal")] private static extern bool _IsJailBroken(); [DllImport("__Internal")] private static extern bool _IsPirated(); [DllImport("__Internal")] private static extern string _GetDeviceID(); [DllImport("__Internal")] private static extern void _SetBackgroundTaskEnabled(bool value); [DllImport("__Internal")] private static extern void _SetEncryptEnabled(bool value); // [DllImport("__Internal")] // private static extern void _SetLatency(int value); [DllImport("__Internal")] private static extern void _CCEvent(string keyPath,int value,string label); #endif #endregion } }