init commit
						commit
						bb1a4b8cce
					
				|  | @ -0,0 +1 @@ | |||
| *.DS_Store | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9bb2904375c2a46eb90e2a3cace489a0 | ||||
| timeCreated: 1702610996 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: df5ee84bbb0c0495eb6f89444802ffd9 | ||||
| timeCreated: 1703231056 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 44aa37ed74dd4407a9d04a07ccf97247 | ||||
| timeCreated: 1702611095 | ||||
|  | @ -0,0 +1,93 @@ | |||
| using UnityEngine; | ||||
| using Guru; | ||||
| using NUnit.Framework; | ||||
| 
 | ||||
| namespace Guru.Editor | ||||
| { | ||||
|     using System.IO; | ||||
|     using UnityEditor; | ||||
|     using Guru.LitJson; | ||||
|      | ||||
|     public class EditorGuruServiceIO | ||||
|     { | ||||
|         private static readonly string DefaultFileName = "guru-service"; | ||||
| 
 | ||||
|         private static string DefaultFilePath = | ||||
|             Path.GetFullPath(Path.Combine(Application.dataPath, $"{DefaultFileName}.json")); | ||||
| 
 | ||||
|         private static string _selectedFilePath = ""; | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 加载配置 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public static GuruServiceConfig LoadConfig() | ||||
|         { | ||||
|             var a = AssetDatabase.FindAssets($"*{DefaultFileName}* t:TextAsset"); | ||||
|             if (a == null || a.Length == 0) | ||||
|             { | ||||
|                 Debug.Log($"<color=orange>--- Can't ind guru-services file</color>"); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 var p = AssetDatabase.GUIDToAssetPath(a[0]); | ||||
|                 var fp = Path.GetFullPath(p); | ||||
|                 if (File.Exists(fp)) _selectedFilePath = fp; | ||||
|                 var t = AssetDatabase.LoadAssetAtPath<TextAsset>(p); | ||||
|                 // Debug.Log($"<color=#88ff00>--- find services file:{p} \n{t.text}</color>"); | ||||
|                 return JsonMapper.ToObject<GuruServiceConfig>(t.text); | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 保存配置 | ||||
|         /// </summary> | ||||
|         /// <param name="config"></param> | ||||
|         internal static void SaveConfig(GuruServiceConfig config = null) | ||||
|         { | ||||
|             if (config == null) | ||||
|             { | ||||
|                 config = new GuruServiceConfig();     | ||||
|             } | ||||
| 
 | ||||
|             var jw = new JsonWriter() | ||||
|             { | ||||
|                 PrettyPrint = true, | ||||
|             }; | ||||
|             JsonMapper.ToJson(config, jw); | ||||
| 
 | ||||
|             var json = jw.ToString(); | ||||
| 
 | ||||
|             if (string.IsNullOrEmpty(_selectedFilePath)) _selectedFilePath = DefaultFilePath; | ||||
|             File.WriteAllText(_selectedFilePath, json); | ||||
|             Debug.Log($"Save config to {_selectedFilePath}"); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 创建空配置 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         internal static GuruServiceConfig CreateEmpty() | ||||
|         { | ||||
|             var cfg = new GuruServiceConfig(); | ||||
|             cfg.version = GuruSDK.Version; | ||||
|             cfg.app_settings = new GuruAppSettings(); | ||||
|             cfg.ad_settings = new GuruAdSettings(); | ||||
|             cfg.adjust_settings = new GuruAdjustSettings(); | ||||
|             cfg.fb_settings = new GuruFbSettings(); | ||||
|             return cfg; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         [Test] | ||||
|         public static void Test_SaveConfig() | ||||
|         { | ||||
|             var cfg = CreateEmpty();  | ||||
|             SaveConfig(cfg); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 043619bc8571240f6b8926c2ccffbd29 | ||||
| timeCreated: 1702877769 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: eec1c72fa3d0c493b9b30091a81043ee | ||||
| timeCreated: 1703413024 | ||||
|  | @ -0,0 +1,40 @@ | |||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="ball.sort.puzzle.color.game.bubble.sorting.free" android:versionCode="1" android:versionName="1.0"> | ||||
|   <application android:label="@string/app_name" android:icon="@drawable/app_icon"> | ||||
|     <!-- The MessagingUnityPlayerActivity is a class that extends | ||||
|          UnityPlayerActivity to work around a known issue when receiving | ||||
|          notification data payloads in the background. --> | ||||
|     <activity android:name="com.google.firebase.MessagingUnityPlayerActivity"  | ||||
|               android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen"> | ||||
|       <intent-filter> | ||||
|         <action android:name="android.intent.action.MAIN" /> | ||||
|         <category android:name="android.intent.category.LAUNCHER" /> | ||||
|       </intent-filter> | ||||
|       <meta-data android:name="unityplayer.UnityActivity" android:value="true" /> | ||||
|     </activity> | ||||
|     <service android:name="com.google.firebase.messaging.MessageForwardingService" android:permission="android.permission.BIND_JOB_SERVICE" android:exported="false"> | ||||
|     </service> | ||||
|     <receiver android:name="com.adjust.sdk.AdjustReferrerReceiver" android:permission="android.permission.INSTALL_PACKAGES" android:exported="true"> | ||||
|       <intent-filter> | ||||
|         <action android:name="com.android.vending.INSTALL_REFERRER" /> | ||||
|       </intent-filter> | ||||
|     </receiver> | ||||
|     <activity android:name="com.facebook.unity.FBUnityLoginActivity" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityDialogsActivity" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityGamingServicesFriendFinderActivity" android:configChanges="fontScale|keyboard|keyboardHidden|locale|mnc|mcc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|uiMode|touchscreen" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityAppLinkActivity" android:exported="true" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityDeepLinkingActivity" android:exported="true" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityGameRequestActivity" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityCreateGameGroupActivity" /> | ||||
|     <activity android:name="com.facebook.unity.FBUnityJoinGameGroupActivity" /> | ||||
|     <meta-data android:name="com.facebook.sdk.ApplicationId" android:value="fb111111111111111" /> | ||||
|     <meta-data android:name="com.facebook.sdk.AutoLogAppEventsEnabled" android:value="false" /> | ||||
|     <meta-data android:name="com.facebook.sdk.AdvertiserIDCollectionEnabled" android:value="true" /> | ||||
|     <provider android:name="com.facebook.FacebookContentProvider" android:authorities="com.facebook.app.FacebookContentProvider.000" android:exported="true" /> | ||||
|     <meta-data name="com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION" value="true" /> | ||||
|     <meta-data name="com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING" value="true" /> | ||||
|   </application> | ||||
|   <uses-permission android:name="android.permission.INTERNET" /> | ||||
|   <uses-permission android:name="com.google.android.finsky.permission.BIND_GET_INSTALL_REFERRER_SERVICE" /> | ||||
|   <uses-permission android:name="com.google.android.gms.permission.AD_ID" /> | ||||
| </manifest> | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: ad463c22214a24eecba0c3d3428cd2bc | ||||
| timeCreated: 1703413179 | ||||
|  | @ -0,0 +1,9 @@ | |||
| org.gradle.jvmargs=-Xmx**JVM_HEAP_SIZE**M | ||||
| org.gradle.parallel=true | ||||
| android.enableR8=**MINIFY_WITH_R_EIGHT** | ||||
| unityStreamingAssets=**STREAMING_ASSETS** | ||||
| # Android Resolver Properties Start | ||||
| android.useAndroidX=true | ||||
| android.enableJetifier=true | ||||
| # Android Resolver Properties End | ||||
| **ADDITIONAL_PROPERTIES** | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 91158a71185444f2798701c44312902f | ||||
| timeCreated: 1703468454 | ||||
|  | @ -0,0 +1,66 @@ | |||
| apply plugin: 'com.android.application' | ||||
| 
 | ||||
| dependencies { | ||||
|     implementation project(':unityLibrary') | ||||
|     } | ||||
| 
 | ||||
| android { | ||||
|     compileSdkVersion **APIVERSION** | ||||
|     buildToolsVersion '**BUILDTOOLS**' | ||||
| 
 | ||||
|     compileOptions { | ||||
|         sourceCompatibility JavaVersion.VERSION_1_8 | ||||
|         targetCompatibility JavaVersion.VERSION_1_8 | ||||
|     } | ||||
| 
 | ||||
|     defaultConfig { | ||||
|         minSdkVersion **MINSDKVERSION** | ||||
|         targetSdkVersion **TARGETSDKVERSION** | ||||
|         applicationId '**APPLICATIONID**' | ||||
|         ndk { | ||||
|             abiFilters **ABIFILTERS** | ||||
|         } | ||||
|         versionCode **VERSIONCODE** | ||||
|         versionName '**VERSIONNAME**' | ||||
|     } | ||||
| 
 | ||||
|     aaptOptions { | ||||
|         noCompress = **BUILTIN_NOCOMPRESS** + unityStreamingAssets.tokenize(', ') | ||||
|         ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" | ||||
|     }**SIGN** | ||||
| 
 | ||||
|     lintOptions { | ||||
|         abortOnError false | ||||
|         checkReleaseBuilds false | ||||
|     } | ||||
| 
 | ||||
|     buildTypes { | ||||
|         debug { | ||||
|             minifyEnabled **MINIFY_DEBUG** | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG** | ||||
|             jniDebuggable true | ||||
|         } | ||||
|         release { | ||||
|             minifyEnabled **MINIFY_RELEASE** | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt')**SIGNCONFIG** | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     packagingOptions { | ||||
|         exclude("META-INF/*.kotlin_module") | ||||
|     } | ||||
|      | ||||
|     **PLAY_ASSET_PACKS****SPLITS** | ||||
| **BUILT_APK_LOCATION** | ||||
|     bundle { | ||||
|         language { | ||||
|             enableSplit = false | ||||
|         } | ||||
|         density { | ||||
|             enableSplit = false | ||||
|         } | ||||
|         abi { | ||||
|             enableSplit = true | ||||
|         } | ||||
|     } | ||||
| }**SPLITS_VERSION_CODE****LAUNCHER_SOURCE_BUILD_SETUP** | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 5ca7eb01ab20749d7b9254c3a4825e31 | ||||
| TextScriptImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,7 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 6cf3317fddf61454181264b523a2804e | ||||
| TextScriptImporter: | ||||
|   externalObjects: {} | ||||
|   userData:  | ||||
|   assetBundleName:  | ||||
|   assetBundleVariant:  | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f9253ec9aa37d4fd28af570d9427c00b | ||||
| timeCreated: 1702629767 | ||||
|  | @ -0,0 +1,113 @@ | |||
| using System.Collections; | ||||
| using Unity.EditorCoroutines.Editor; | ||||
| 
 | ||||
| namespace Guru.Editor | ||||
| { | ||||
|     using NUnit.Framework; | ||||
|     using UnityEditor; | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|     using System.IO; | ||||
|     using System.Xml; | ||||
|      | ||||
|     public static class AndroidManifestMod | ||||
|     { | ||||
|         private const string TargetPath = "Plugins/Android/AndroidManifest.xml"; | ||||
|         private const string ValOptimizeInitialization = "com.google.android.gms.ads.flag.OPTIMIZE_INITIALIZATION"; | ||||
|         private const string ValOptimizeAdLoading = "com.google.android.gms.ads.flag.OPTIMIZE_AD_LOADING"; | ||||
| 
 | ||||
|         private static string TargetFullPath = Path.Combine(Application.dataPath, TargetPath); | ||||
|          | ||||
|         public static bool IsManifestExist() => File.Exists(TargetFullPath); | ||||
| 
 | ||||
|         public static void Apply() | ||||
|         { | ||||
|             if (!IsManifestExist()) | ||||
|             { | ||||
|                 CopyManifest(); | ||||
|                 return; | ||||
|             } | ||||
|              | ||||
|             var doc = new XmlDocument(); | ||||
|             doc.Load(TargetFullPath); | ||||
| 
 | ||||
|             var rootNode = doc.SelectSingleNode("manifest/application"); | ||||
|             int item1 = 0; | ||||
|             int item2 = 0; | ||||
|              | ||||
|             XmlNodeList metadatas = rootNode.SelectNodes("meta-data"); | ||||
|             if (metadatas != null && metadatas.Count > 0) | ||||
|             { | ||||
|                 bool isDirty = false; | ||||
|        | ||||
|                 foreach (XmlElement e in metadatas) | ||||
|                 { | ||||
|                     if (e != null) | ||||
|                     { | ||||
|                         if (e.HasAttribute("android:name")) | ||||
|                         { | ||||
|                             if (e.Attributes["android:name"].Value == ValOptimizeInitialization) item1 = 1; | ||||
|                             if (e.Attributes["android:name"].Value == ValOptimizeAdLoading) item2 = 1; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             string androidSP = "http://schemas.android.com/apk/res/android"; | ||||
|              | ||||
|             if (item1 == 0) | ||||
|             { | ||||
|                var e =  doc.CreateElement("meta-data"); | ||||
|                e.SetAttribute("name",androidSP, ValOptimizeInitialization); | ||||
|                e.SetAttribute("value",androidSP, "true"); | ||||
|                rootNode.AppendChild(e); | ||||
|             } | ||||
|              | ||||
|             if (item2 == 0) | ||||
|             { | ||||
|                 var e =  doc.CreateElement("meta-data"); | ||||
|                 e.SetAttribute("name",androidSP,ValOptimizeAdLoading); | ||||
|                 e.SetAttribute("value",androidSP, "true"); | ||||
|                 rootNode.AppendChild(e); | ||||
|             } | ||||
| 
 | ||||
|             var rootE = doc.SelectSingleNode("manifest") as XmlElement; | ||||
|             if (rootE != null) | ||||
|             { | ||||
|                 rootE.Attributes["package"].Value = PlayerSettings.applicationIdentifier; // 写入包名 | ||||
|             } | ||||
| 
 | ||||
|             doc.Save(TargetFullPath); | ||||
|         } | ||||
| 
 | ||||
|         private static void CopyManifest() | ||||
|         { | ||||
|             if (File.Exists(TargetFullPath)) return; | ||||
|              | ||||
|             var path = GuruEditorHelper.GetFilePath($"{nameof(AndroidManifestMod)}.cs t:Script"); | ||||
|             if (!string.IsNullOrEmpty(path)) | ||||
|             { | ||||
|                 var files = Path.GetFullPath($"{path}/../Files"); | ||||
|                 var from = $"{files}/AndroidManifest.txt"; | ||||
|                 if (File.Exists(from)) | ||||
|                 { | ||||
|                     File.Copy(from, TargetFullPath); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #region Testing | ||||
| 
 | ||||
|         [Test] | ||||
|         public static void Test_Injection() | ||||
|         { | ||||
|             Apply(); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9ce9c7008577c4c04b10eb96a3244867 | ||||
| timeCreated: 1703409620 | ||||
|  | @ -0,0 +1,117 @@ | |||
| using System.Linq; | ||||
| 
 | ||||
| namespace Guru.Editor | ||||
| { | ||||
|     using UnityEditor; | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|     using System.IO; | ||||
|     public class AndroidProjectMod | ||||
|     { | ||||
|         private static readonly int TargetSDKVersion = 33; | ||||
|          | ||||
|         private static readonly string LauncherName = "launcherTemplate"; | ||||
|         private static string LauncherFullPath = Path.Combine(Application.dataPath, $"Plugins/Android/{LauncherName}.gradle"); | ||||
|          | ||||
|         private static readonly string MainName = "mainTemplate"; | ||||
|         private static string MainFullPath = Path.Combine(Application.dataPath,  $"Plugins/Android/{MainName}.gradle"); | ||||
|          | ||||
|         private static readonly string PropertiesName = "gradleTemplate"; | ||||
|         private static string PropertiesFullPath = Path.Combine(Application.dataPath,  $"Plugins/Android/{PropertiesName}.properties"); | ||||
|          | ||||
|         public static void Apply() | ||||
|         { | ||||
|             FixLauncher(); | ||||
|             FixMain(); | ||||
|             FixProperties(); | ||||
|             CheckTargetSDKVersion(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private static void FixLauncher() | ||||
|         { | ||||
|             if (!File.Exists(LauncherFullPath)) | ||||
|             { | ||||
|                 CopyFile($"{LauncherName}.txt", LauncherFullPath); | ||||
|                 Debug.Log($"[MOD] --- Copy file to: {LauncherFullPath}"); | ||||
|                 return; | ||||
|             } | ||||
| 
 | ||||
|             var ptn1 = "**PACKAGING_OPTIONS**"; | ||||
|             var ptn2 = "abortOnError false"; | ||||
|             var lines = File.ReadAllLines(LauncherFullPath); | ||||
| 
 | ||||
|             string line = ""; | ||||
|             for (int i = 0; i < lines.Length; i++) | ||||
|             { | ||||
|                 line = lines[i]; | ||||
|                 if (line.Contains(ptn1)) | ||||
|                 { | ||||
|                     lines[i] = line.Replace(ptn1, "\n\n\tpackagingOptions {\n\t\texclude(\"META-INF/*.kotlin_module\")\n\t}\n\n"); | ||||
|                 } | ||||
| 
 | ||||
|                 if (line.Contains(ptn2)) | ||||
|                 { | ||||
|                     if (lines[i + 1].Contains("}")) | ||||
|                     { | ||||
|                         lines[i + 1] = lines[i + 1].Replace("}", "\tcheckReleaseBuilds false\n\t}"); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             Debug.Log($"[MOD] --- Fix file at: {LauncherFullPath}"); | ||||
|             File.WriteAllLines(LauncherFullPath, lines); | ||||
| 
 | ||||
|         } | ||||
|         private static void FixMain() | ||||
|         { | ||||
|             if (!File.Exists(MainFullPath)) | ||||
|             { | ||||
|                 Debug.Log($"[MOD] --- Copy file to: {MainFullPath}"); | ||||
|                 CopyFile($"{MainName}.txt", MainFullPath); | ||||
|             } | ||||
|         } | ||||
|         private static void FixProperties() | ||||
|         { | ||||
|             if (!File.Exists(PropertiesFullPath)) | ||||
|             { | ||||
|                 Debug.Log($"[MOD] --- Copy file to: {PropertiesFullPath}"); | ||||
|                 CopyFile($"{PropertiesName}.txt", PropertiesFullPath); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private static void CheckTargetSDKVersion() | ||||
|         { | ||||
|             var ver = (int) PlayerSettings.Android.targetSdkVersion; | ||||
|             if (ver < TargetSDKVersion) | ||||
|             { | ||||
|                 Debug.Log($"[MOD] --- Fix target sdk version -> {TargetSDKVersion}"); | ||||
|                 PlayerSettings.Android.targetSdkVersion = (AndroidSdkVersions)TargetSDKVersion; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #region File IO | ||||
| 
 | ||||
|         private static string GetMoveFilePath(string fileName) | ||||
|         { | ||||
|             var path = GuruEditorHelper.GetFilePath($"{nameof(AndroidProjectMod)}.cs t:Script"); | ||||
|             var files = Path.GetFullPath($"{path}/../Files"); | ||||
|             return $"{files}/{fileName}"; | ||||
|         } | ||||
|         private static void CopyFile(string fileName, string toPath) | ||||
|         { | ||||
|             var from = GetMoveFilePath(fileName); | ||||
|             if (!string.IsNullOrEmpty(from)) | ||||
|             { | ||||
|                 if (File.Exists(from)) | ||||
|                 { | ||||
|                     File.Copy(from, toPath); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 3e096221d72bd44baa543f1629092c4a | ||||
| timeCreated: 1703412483 | ||||
|  | @ -0,0 +1,17 @@ | |||
| namespace Guru.Editor | ||||
| { | ||||
|     using UnityEditor; | ||||
|     public class GuruEditorHelper | ||||
|     { | ||||
|         public static string GetFilePath(string filter) | ||||
|         { | ||||
|             var guids = AssetDatabase.FindAssets(filter); | ||||
|             if (guids != null && guids.Length > 0) | ||||
|             { | ||||
|                 var path = AssetDatabase.GUIDToAssetPath(guids[0]); | ||||
|                 return path; | ||||
|             } | ||||
|             return ""; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: d05ef4ba47b6e4cb7bf95cb073af4915 | ||||
| timeCreated: 1703413245 | ||||
|  | @ -0,0 +1,69 @@ | |||
| 
 | ||||
| 
 | ||||
| namespace Guru.Editor | ||||
| { | ||||
|     using UnityEditor; | ||||
|     using System.IO; | ||||
|     using UnityEngine; | ||||
|     using System.Collections; | ||||
|     using Guru.Editor; | ||||
|     using Unity.EditorCoroutines.Editor; | ||||
|      | ||||
|     public class GuruSDKBooster | ||||
|     { | ||||
|          | ||||
|         // [MenuItem("Test/API/Test CR")] | ||||
|         static void TestCR() | ||||
|         { | ||||
|            // EditorHelper.StartCoroutine(OnTestRun()); | ||||
|            EditorCoroutineUtility.StartCoroutineOwnerless(OnTestRun()); | ||||
|         } | ||||
|          | ||||
|         static IEnumerator OnTestRun() | ||||
|         { | ||||
|             int i = 0; | ||||
|             while (i < 5) | ||||
|             { | ||||
|                 Debug.Log($"--- ticket: {i}"); | ||||
|                 i++; | ||||
|                 yield return new EditorWaitForSeconds(1); | ||||
|             } | ||||
|             Debug.Log($"------- runner end -------"); | ||||
|         } | ||||
|     } | ||||
|      | ||||
|      | ||||
| 
 | ||||
|     // [InitializeOnLoad] | ||||
|     internal class BoostOnLoad | ||||
|     { | ||||
|         static BoostOnLoad() | ||||
|         { | ||||
|             var config = EditorGuruServiceIO.LoadConfig(); | ||||
|             if (null != config) | ||||
|             { | ||||
|                 Debug.Log("<color=#88ff00>found guru-services file on disk</color>"); | ||||
|                 // TODO: | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Debug.Log("<color=yellow>Can't find guru-services.json on load...</color>"); | ||||
|                 // GuruSDKManager.Open(); | ||||
|                 EditorGuruServiceIO.LoadConfig(); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
|     } | ||||
|      | ||||
|      | ||||
|      | ||||
|      | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 4012c7bdb57bc4bfbb3b313a86ea3901 | ||||
| timeCreated: 1702627784 | ||||
|  | @ -0,0 +1,16 @@ | |||
| using Guru.Editor; | ||||
| using UnityEditor; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     public class GuruSDKMenuItems | ||||
|     { | ||||
| 
 | ||||
|         [MenuItem("Guru/Guru SDK")] | ||||
|         private static void ShowGuruManager() | ||||
|         { | ||||
|             GuruSDKManager.Open(); | ||||
|         } | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 7e6a90bd7ba03491d87943c2c1fcf17e | ||||
| timeCreated: 1702861089 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 627835e82d65043cf8996da4a8377fa7 | ||||
| timeCreated: 1703231041 | ||||
|  | @ -0,0 +1,887 @@ | |||
| 
 | ||||
| 
 | ||||
| using System.Collections.Generic; | ||||
| using System.IO; | ||||
| using Facebook.Unity.Settings; | ||||
| using UnityEditor.Compilation; | ||||
| 
 | ||||
| namespace Guru.Editor | ||||
| { | ||||
|     using System; | ||||
|     using UnityEditor; | ||||
|     using UnityEngine; | ||||
|     using Guru; | ||||
|     using AppLovinMax.Scripts.IntegrationManager.Editor; | ||||
|      | ||||
|      | ||||
|     public class GuruSDKManager: EditorWindow | ||||
|     { | ||||
|         private const string GURU_SETTINGS_PATH = "Assets/Guru/Resources/GuruSettings.asset"; | ||||
|         private const string APPLOVIN_SETTINGS_PATH = "Assets/Guru/Resources/AppLovinSettings.asset"; | ||||
|         private const string FACEBOOK_SETTINGS_PATH = "Assets/FacebookSDK/SDK/Resources/FacebookSettings.asset"; | ||||
|         private const string ANDROID_KEYSTORE_PATH = "Packages/com.guru.unity.sdk.core/Keystore/guru.jks"; | ||||
|         private const string KeyMaxAutoUpdateEnabled = "com.applovin.auto_update_enabled"; | ||||
|          | ||||
|          | ||||
|         private static GuruSDKManager _instance; | ||||
|         public static GuruSDKManager Instance { | ||||
|             get | ||||
|             { | ||||
|                 if (_instance == null) | ||||
|                 { | ||||
|                     _instance = GetWindow<GuruSDKManager>(); | ||||
|                 } | ||||
|                 return _instance; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private GuruServiceConfig _serviceConfig; | ||||
|         private static GUIStyle _itemTitleStyle; | ||||
|         private static GUIStyle StyleItemTitle | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if (_itemTitleStyle == null) | ||||
|                 { | ||||
|                     _itemTitleStyle = new GUIStyle("BOX") | ||||
|                     { | ||||
|                         fontSize = 12, | ||||
|                         fontStyle = FontStyle.Bold, | ||||
|                         stretchWidth = true, | ||||
|                         alignment = TextAnchor.MiddleLeft, | ||||
|                         padding = new RectOffset(4, 4, 4, 4), | ||||
|                     }; | ||||
|                 } | ||||
|                 return _itemTitleStyle; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         private bool _hasCheckingCompleted = false; | ||||
| 
 | ||||
| 
 | ||||
|         public GuruSDKManager() | ||||
|         { | ||||
|             this.minSize = new Vector2(480, 640); | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         public static void Open() | ||||
|         { | ||||
|             Instance.Show(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private void OnEnable() | ||||
|         { | ||||
|             titleContent = new GUIContent("Guru SDK Manager"); | ||||
|             _serviceConfig = EditorGuruServiceIO.LoadConfig(); | ||||
|             if (_serviceConfig != null) | ||||
|             { | ||||
|                 Debug.Log($"<color=#88ff00>[Guru] Load <guru-services> success.</color>"); | ||||
|                 CheckServicesCompletion(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Debug.Log($"<color=red>[Guru] <guru-services> file not found...</color>"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #region Service Checker | ||||
| 
 | ||||
|         private const string MARK_FAIL = "#FAIL"; | ||||
|         private const string MARK_INDENT = "    "; | ||||
|         private List<string> _completionCheckResult; | ||||
|         private int _serviceCriticalFail = 0; | ||||
|         private int _serviceNormalFail = 0; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 检查服务文件的配置完整性 | ||||
|         /// </summary> | ||||
|         private void CheckServicesCompletion() | ||||
|         { | ||||
|             _serviceCriticalFail = 0; | ||||
|             _serviceNormalFail = 0; | ||||
|              | ||||
|             _completionCheckResult = new List<string>(40); | ||||
|             string mk_yes = " ( \u2714 ) "; | ||||
|             string mk_no = " ( \u2718 ) "; | ||||
|             string mk_star = " ( \u2605 ) "; | ||||
|             string check_passed = $"{MARK_INDENT}{mk_yes} All items passed!"; | ||||
|             if (_serviceConfig == null) | ||||
|             { | ||||
|                 AddResultLine($"{mk_yes} guru-services is missing", false); | ||||
|                 AddResultLine($"Please contact Guru tech support to get help.", false); | ||||
|                 _serviceCriticalFail++; | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 bool passed = true; | ||||
|                 AddResultLine($"{mk_star} <guru-services> exists!"); | ||||
|                 AddResultLine($"--------------------------------"); | ||||
|                  | ||||
|                 //-------- APP Settings -------- | ||||
|                 passed = true; | ||||
|                 AddResultLine($"[ App ]"); | ||||
|                 if (_serviceConfig.app_settings == null) | ||||
|                 { | ||||
|                     passed = false; | ||||
|                     AddResultLine($"{MARK_INDENT}{mk_no} settings is missing!", false); | ||||
|                     _serviceCriticalFail++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (_serviceConfig.app_settings.app_id.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} AppID is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (_serviceConfig.app_settings.bundle_id.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} BundleID is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (_serviceConfig.app_settings.product_name.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Product Name is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (_serviceConfig.app_settings.support_email.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Support Email is missing!", false); | ||||
|                         _serviceNormalFail++; | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 if (passed) AddResultLine(check_passed); | ||||
|                  | ||||
|                 //-------- ADS Settings -------- | ||||
|                 passed = true; | ||||
|                 AddResultLine($"[ Ads ]"); | ||||
|                 if (_serviceConfig.ad_settings == null) | ||||
|                 { | ||||
|                     passed = false; | ||||
|                     AddResultLine($"{MARK_INDENT}{mk_no} settings is missing!", false); | ||||
|                     _serviceCriticalFail++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (_serviceConfig.ad_settings.sdk_key.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} SDK Key is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.admob_app_id)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Admob ID is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.max_ids_android)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} AppLovin Android IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.max_ids_ios)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} AppLovin iOS IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.amazon_ids_android)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Amazon Android IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.amazon_ids_ios)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Amazon iOS IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.pubmatic_ids_android)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Pubmatic Android IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.pubmatic_ids_ios)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Pubmatic iOS IDs is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.moloco_ids_android)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Moloco Android Test IDs is missing!", false); | ||||
|                         _serviceNormalFail++; | ||||
|                     } | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.ad_settings.moloco_ids_ios)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Moloco iOS Test IDs is missing!", false); | ||||
|                         _serviceNormalFail++; | ||||
|                     } | ||||
|                 } | ||||
|                 if (passed) AddResultLine(check_passed); | ||||
|                  | ||||
|                 //-------- Channels Settings -------- | ||||
|                 passed = true; | ||||
|                 AddResultLine($"[ Channels ]"); | ||||
|                 if (_serviceConfig.fb_settings == null) | ||||
|                 { | ||||
|                     passed = false; | ||||
|                     AddResultLine($"{MARK_INDENT}{mk_no} Facebook settings is missing!", false); | ||||
|                     _serviceCriticalFail++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if (_serviceConfig.fb_settings.app_id.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Facebook AppID is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                     if (_serviceConfig.fb_settings.client_token.IsNullOrEmpty()) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Facebook Client Token is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                 } | ||||
| 
 | ||||
|                 if (_serviceConfig.adjust_settings == null) | ||||
|                 { | ||||
|                     passed = false; | ||||
|                     AddResultLine($"{MARK_INDENT}{mk_no} Adjust settings is missing!", false); | ||||
|                     _serviceCriticalFail++; | ||||
|                 } | ||||
|                 else | ||||
|                 { | ||||
|                     if(!IsArrayNotEmpty(_serviceConfig.adjust_settings.app_token)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Adjust AppToken is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
| 
 | ||||
|                     if (!IsArrayNotEmpty(_serviceConfig.adjust_settings.events)) | ||||
|                     { | ||||
|                         passed = false; | ||||
|                         AddResultLine($"{MARK_INDENT}{mk_no} Adjust Events is missing!", false); | ||||
|                         _serviceCriticalFail++; | ||||
|                     } | ||||
|                 } | ||||
|                 if (passed) AddResultLine(check_passed); | ||||
|                  | ||||
|                 //-------- IAP -------- | ||||
|                 passed = true; | ||||
|                 AddResultLine($"[ IAP ]"); | ||||
|                 if (!IsArrayNotEmpty(_serviceConfig.products)) | ||||
|                 { | ||||
|                     passed = false; | ||||
|                     AddResultLine($"{MARK_INDENT}{mk_no} Product list is missing!", false); | ||||
|                     _serviceNormalFail++; | ||||
|                 } | ||||
|                 if (passed) AddResultLine(check_passed); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private void AddResultLine(string msg, bool passed = true) | ||||
|         { | ||||
|             if (_completionCheckResult == null) | ||||
|             { | ||||
|                 _completionCheckResult = new List<string>(40); | ||||
|             } | ||||
|             string mk = passed? "" : MARK_FAIL; | ||||
|             _completionCheckResult.Add($"{msg}{mk}"); | ||||
|         } | ||||
| 
 | ||||
|         private void GUI_ServiceCheckResult() | ||||
|         { | ||||
|             if (_completionCheckResult != null) | ||||
|             { | ||||
|                 Color green = new Color(0.7f, 1, 0); | ||||
|                 Color red = new Color(1, 0.2f, 0); | ||||
|                 Color c; | ||||
|                 string line = ""; | ||||
|                 for (int i = 0; i < _completionCheckResult.Count; i++) | ||||
|                 { | ||||
|                     c = green; | ||||
|                     line = _completionCheckResult[i]; | ||||
|                     if (line.EndsWith(MARK_FAIL)) | ||||
|                     { | ||||
|                         line = line.Replace(MARK_FAIL, ""); | ||||
|                         c = red; | ||||
|                     } | ||||
|                     GUI_Color(c, () => | ||||
|                     { | ||||
|                         EditorGUILayout.LabelField(line); | ||||
|                         GUILayout.Space(2); | ||||
|                     }); | ||||
|                      | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
|         #region GUI | ||||
| 
 | ||||
|         void OnGUI() | ||||
|         { | ||||
|             // TITLE | ||||
|             GUI_WindowTitle(); | ||||
|              | ||||
|             // CONTENT | ||||
|             if (_serviceConfig == null) | ||||
|             { | ||||
|                 GUI_OnConfigDisabled(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 GUI_OnConfigEnabled(); | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
|         private void GUI_WindowTitle() | ||||
|         { | ||||
|             GUILayout.Space(4); | ||||
|              | ||||
|             var s = new GUIStyle("BOX") | ||||
|             { | ||||
|                 fontSize = 36, | ||||
|                 fontStyle = FontStyle.Bold, | ||||
|                 alignment = TextAnchor.MiddleCenter, | ||||
|                 stretchWidth = true, | ||||
|                 stretchHeight = true, | ||||
|                 fixedHeight = 60, | ||||
|             }; | ||||
| 
 | ||||
| 
 | ||||
|             EditorGUILayout.LabelField("Guru SDK",s); | ||||
|             s.fontSize = 13; | ||||
|             s.fixedHeight = 20; | ||||
|             EditorGUILayout.LabelField($"Version {GuruSDK.Version}", s); | ||||
|              | ||||
|             GUILayout.Space(4); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 配置不可用 | ||||
|         /// </summary> | ||||
|         private void GUI_OnConfigDisabled() | ||||
|         { | ||||
|             GUI_Color(new Color(1,0.2f, 0), () => | ||||
|             { | ||||
|                 EditorGUILayout.LabelField("<>", StyleItemTitle); | ||||
|             }); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 配置可用 | ||||
|         /// </summary> | ||||
|         private void GUI_OnConfigEnabled() | ||||
|         { | ||||
|             var box = new GUIStyle("BOX"); | ||||
|             float btnH = 40; | ||||
|              | ||||
|             //------------ check allsettings ------------- | ||||
|             EditorGUILayout.LabelField("[ Guru Service ]", StyleItemTitle); | ||||
|             GUILayout.Space(2); | ||||
|             GUI_ServiceCheckResult(); | ||||
|             GUILayout.Space(16); | ||||
| 
 | ||||
|             if (_serviceCriticalFail > 0) | ||||
|             { | ||||
|                 // 严重错误过多 | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 GUI_Button("IMPORT ALL SETTINGS", () => | ||||
|                 { | ||||
|                     CheckAllComponents(); | ||||
|                 }, null, GUILayout.Height(btnH)); | ||||
|             } | ||||
|              | ||||
|             GUILayout.Space(4); | ||||
|           | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|         #region Check Components | ||||
| 
 | ||||
|         private string logBuffer; | ||||
|          | ||||
|          | ||||
|         private void CheckAllComponents() | ||||
|         { | ||||
|             string barTitle = "Setup All Components"; | ||||
|             EditorUtility.DisplayCancelableProgressBar(barTitle, "Start collect all components", 0); | ||||
|             Debug.Log("--- Setup All Components ---"); | ||||
|             ImportGuruSettings(); | ||||
|             EditorUtility.DisplayCancelableProgressBar(barTitle, "GuruSettings is done", 0.2f); | ||||
|             ImportAppLovinSettings(); | ||||
|             EditorUtility.DisplayCancelableProgressBar(barTitle, "AppLovinSettings is done", 0.4f); | ||||
|             ImportFacebookSettings(); | ||||
|             EditorUtility.DisplayCancelableProgressBar(barTitle, "FacebookSettings is done", 0.6f); | ||||
|             ApplyMods(); | ||||
|             EditorUtility.DisplayCancelableProgressBar(barTitle, "All Mods is done", 0.8f);   | ||||
|              | ||||
|             AssetDatabase.SaveAssets(); | ||||
|              | ||||
|             CompilationPipeline.RequestScriptCompilation(); | ||||
|             CompilationPipeline.compilationFinished += o => | ||||
|             { | ||||
|                 EditorUtility.ClearProgressBar(); | ||||
|                 AssetDatabase.Refresh(); | ||||
| 
 | ||||
|                 EditorUtility.DisplayDialog("Importing Guru Services", "All the settings importing success!", "OK"); | ||||
|             }; | ||||
|         } | ||||
| 
 | ||||
|         //------------------------- GuruSettings -------------------------------- | ||||
|         private void ImportGuruSettings() | ||||
|         { | ||||
|             GuruSettings settings = null; | ||||
|             if (IsAssetExists(nameof(GuruSettings), GURU_SETTINGS_PATH)) | ||||
|             { | ||||
|                 settings = AssetDatabase.LoadAssetAtPath<GuruSettings>(GURU_SETTINGS_PATH); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 settings = CreateInstance<GuruSettings>(); | ||||
|                 AssetDatabase.CreateAsset(settings, GURU_SETTINGS_PATH); | ||||
|             } | ||||
|             settings.CompanyName = "Guru"; | ||||
|             settings.ProductName = _serviceConfig.app_settings.product_name; | ||||
|             settings.GameIdentifier = _serviceConfig.app_settings.bundle_id; | ||||
|             settings.PriacyUrl = _serviceConfig.app_settings.privacy_url; | ||||
|             settings.TermsUrl = _serviceConfig.app_settings.terms_url; | ||||
|             settings.SupportEmail = _serviceConfig.app_settings.support_email; | ||||
|             settings.AndroidStoreUrl = _serviceConfig.app_settings.android_store; | ||||
|             settings.IOSStoreUrl = _serviceConfig.app_settings.ios_store; | ||||
|              | ||||
|             SerializedObject so = new SerializedObject(settings); | ||||
|             SerializedProperty n; | ||||
|             SerializedObject nn; | ||||
|             SerializedProperty p; | ||||
|             string[] arr; | ||||
|              | ||||
|             n = so.FindProperty("IPMSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("IPMSetting.appID"); | ||||
|                 p.stringValue = _serviceConfig.app_settings.app_id; | ||||
|                  | ||||
|                 p = n.serializedObject.FindProperty("IPMSetting.tokenValidTime"); | ||||
|                 p.intValue = _serviceConfig.app_settings.token_vaild_time; | ||||
|             } | ||||
| 
 | ||||
|             //---------- AMAZON ----------------------- | ||||
|             n = so.FindProperty("AmazonSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("AmazonSetting.Enable"); | ||||
|                 p.boolValue = true; | ||||
|                  | ||||
|                 arr = _serviceConfig.ad_settings.amazon_ids_android; | ||||
|                 if (IsArrayHasLength(arr, 4)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.Android.appID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.Android.bannerSlotID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.Android.interSlotID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.Android.rewardSlotID"); | ||||
|                     p.stringValue = arr[3]; | ||||
|                 } | ||||
| 
 | ||||
|                 arr = _serviceConfig.ad_settings.amazon_ids_ios; | ||||
|                 if (IsArrayHasLength(arr, 4)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.iOS.appID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.iOS.bannerSlotID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.iOS.interSlotID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                     p = n.serializedObject.FindProperty("AmazonSetting.iOS.rewardSlotID"); | ||||
|                     p.stringValue = arr[3]; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             //---------- PUBMATIC ----------------------- | ||||
|             n = so.FindProperty("PubmaticSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("PubmaticSetting.Enable"); | ||||
|                 p.boolValue = true; | ||||
|                  | ||||
|                 arr = _serviceConfig.ad_settings.pubmatic_ids_android; | ||||
|                 if (IsArrayHasLength(arr, 4)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.Android.storeUrl"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.Android.bannerUnitID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.Android.interUnitID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.Android.rewardUnitID"); | ||||
|                     p.stringValue = arr[3]; | ||||
|                 } | ||||
| 
 | ||||
|                 arr = _serviceConfig.ad_settings.pubmatic_ids_ios; | ||||
|                 if (IsArrayHasLength(arr, 4)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.iOS.storeUrl"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.iOS.bannerUnitID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.iOS.interUnitID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                     p = n.serializedObject.FindProperty("PubmaticSetting.iOS.rewardUnitID"); | ||||
|                     p.stringValue = arr[3]; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             //---------- MOLOCO ----------------------- | ||||
|             n = so.FindProperty("MolocoSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("MolocoSetting.Enable"); | ||||
|                 p.boolValue = true; | ||||
|                  | ||||
|                 arr = _serviceConfig.ad_settings.moloco_ids_android; | ||||
|                 if (IsArrayHasLength(arr, 3)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.Android.bannerTestUnitID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.Android.interTestUnitID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.Android.rewardTestUnitID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                 } | ||||
| 
 | ||||
|                 arr = _serviceConfig.ad_settings.moloco_ids_ios; | ||||
|                 if (IsArrayHasLength(arr, 3)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.iOS.bannerTestUnitID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.iOS.interTestUnitID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("MolocoSetting.iOS.rewardTestUnitID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             //----------- ADSettings ------------------- | ||||
|             n = so.FindProperty("ADSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("ADSetting.SDK_KEY"); | ||||
|                 p.stringValue = _serviceConfig.ad_settings.sdk_key; | ||||
|                  | ||||
|                 arr = _serviceConfig.ad_settings.max_ids_android; | ||||
|                 if(IsArrayHasLength(arr, 3)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.Android_Banner_ID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.Android_Interstitial_ID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.Android_Rewarded_ID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                 } | ||||
|                  | ||||
|                 arr = _serviceConfig.ad_settings.max_ids_ios; | ||||
|                 if (IsArrayHasLength(arr, 3)) | ||||
|                 { | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.IOS_Banner_ID"); | ||||
|                     p.stringValue = arr[0]; | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.IOS_Interstitial_ID"); | ||||
|                     p.stringValue = arr[1]; | ||||
|                     p = n.serializedObject.FindProperty("ADSetting.IOS_Rewarded_ID"); | ||||
|                     p.stringValue = arr[2]; | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             //----------- AdjustSetting ------------------- | ||||
|             n = so.FindProperty("AdjustSetting"); | ||||
|             if (null != n  | ||||
|                 && IsArrayHasLength(_serviceConfig.adjust_settings.app_token, 2)) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("AdjustSetting.androidAppToken"); | ||||
|                 p.stringValue = _serviceConfig.adjust_settings.app_token[0]; | ||||
|                  | ||||
|                 p = n.serializedObject.FindProperty("AdjustSetting.iOSAppToken"); | ||||
|                 p.stringValue = _serviceConfig.adjust_settings.app_token[1]; | ||||
|             } | ||||
| 
 | ||||
|             //----------- AnalyticsSetting ------------------- | ||||
|             n = so.FindProperty("AnalyticsSetting"); | ||||
|             if (null != n) | ||||
|             { | ||||
|                 p = n.serializedObject.FindProperty("AnalyticsSetting.levelEndSuccessNum"); | ||||
|                 p.intValue = _serviceConfig.app_settings.level_end_success_num; | ||||
|                 p = n.serializedObject.FindProperty("AnalyticsSetting.enalbeFirebaseAnalytics"); | ||||
|                 p.boolValue = _serviceConfig.app_settings.enable_firebase; | ||||
|                 p = n.serializedObject.FindProperty("AnalyticsSetting.enalbeFacebookAnalytics"); | ||||
|                 p.boolValue = _serviceConfig.app_settings.enable_facebook; | ||||
|                 p = n.serializedObject.FindProperty("AnalyticsSetting.enalbeAdjustAnalytics"); | ||||
|                 p.boolValue = _serviceConfig.app_settings.enable_adjust; | ||||
|                 p = n.serializedObject.FindProperty("AnalyticsSetting.adjustEventList"); | ||||
|                 if (null != p && IsArrayNotEmpty(_serviceConfig.adjust_settings.events)) | ||||
|                 { | ||||
|                     p.ClearArray(); | ||||
|                     for (int i = 0; i < _serviceConfig.adjust_settings.events.Length; i++) | ||||
|                     { | ||||
|                         arr = _serviceConfig.adjust_settings.events[i].Split(","); | ||||
|                         if (IsArrayHasLength(arr, 3)) | ||||
|                         { | ||||
|                             p.InsertArrayElementAtIndex(i); | ||||
|                             nn = p.GetArrayElementAtIndex(i).serializedObject; | ||||
|                             nn.FindProperty($"AnalyticsSetting.adjustEventList.Array.data[{i}].EventName").stringValue = arr[0]; | ||||
|                             nn.FindProperty($"AnalyticsSetting.adjustEventList.Array.data[{i}].AndroidToken").stringValue = arr[1]; | ||||
|                             nn.FindProperty($"AnalyticsSetting.adjustEventList.Array.data[{i}].IOSToken").stringValue = arr[2]; | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|              | ||||
|             //---------------- Productions ------------------------ | ||||
|             n = so.FindProperty("Products"); | ||||
|             if (n != null && IsArrayNotEmpty(_serviceConfig.products)) | ||||
|             { | ||||
|                 n.ClearArray(); | ||||
|                 for (int i = 0; i < _serviceConfig.products.Length; i++) | ||||
|                 { | ||||
|                     arr = _serviceConfig.products[i].Split(","); | ||||
|                     if (IsArrayHasLength(arr, 5)) | ||||
|                     { | ||||
|                         n.InsertArrayElementAtIndex(i); | ||||
|                         nn = n.GetArrayElementAtIndex(i).serializedObject; | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].ProductName").stringValue = arr[0]; | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].GooglePlayProductId").stringValue = arr[1]; | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].AppStoreProductId").stringValue = arr[2]; | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].Price").doubleValue = double.Parse(arr[3]); | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].Type").enumValueIndex = int.Parse(arr[4]); | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].IsFree").boolValue = false; | ||||
|                         nn.FindProperty($"Products.Array.data[{i}].Category").stringValue = "Store"; | ||||
|                     }  | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|             //------- Save SO ---------- | ||||
|             so.ApplyModifiedProperties(); | ||||
|             EditorUtility.SetDirty(settings); | ||||
|             AssetDatabase.SaveAssetIfDirty(settings); | ||||
|         } | ||||
| 
 | ||||
|         //------------------------- AppLovinSettings -------------------------------- | ||||
|         private void ImportAppLovinSettings() | ||||
|         { | ||||
|             EditorPrefs.SetBool(KeyMaxAutoUpdateEnabled, false); // 关闭Max自动升级功能 | ||||
|              | ||||
|             AppLovinSettings settings = null; | ||||
|             if (IsAssetExists(nameof(AppLovinSettings), APPLOVIN_SETTINGS_PATH)) | ||||
|             { | ||||
|                 settings = AssetDatabase.LoadAssetAtPath<AppLovinSettings>(APPLOVIN_SETTINGS_PATH); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 settings = CreateInstance<AppLovinSettings>(); | ||||
|                 AssetDatabase.CreateAsset(settings, APPLOVIN_SETTINGS_PATH); | ||||
|             } | ||||
| 
 | ||||
|             settings.SetAttributionReportEndpoint = true; | ||||
|             settings.QualityServiceEnabled = true; | ||||
|             settings.SdkKey = _serviceConfig.ad_settings.sdk_key; | ||||
|             if (IsArrayHasLength(_serviceConfig.ad_settings.admob_app_id, 2)) | ||||
|             { | ||||
|                 settings.AdMobAndroidAppId = _serviceConfig.ad_settings.admob_app_id[0]; | ||||
|                 settings.AdMobIosAppId = _serviceConfig.ad_settings.admob_app_id[1]; | ||||
|             } | ||||
|             settings.ConsentFlowEnabled = false; | ||||
|             EditorUtility.SetDirty(settings); | ||||
|             AssetDatabase.SaveAssetIfDirty(settings); | ||||
|         } | ||||
| 
 | ||||
|         //------------------------- FacebookSettings -------------------------------- | ||||
|         private void ImportFacebookSettings() | ||||
|         { | ||||
|             FacebookSettings settings = null; | ||||
|             if (IsAssetExists(nameof(FacebookSettings), FACEBOOK_SETTINGS_PATH)) | ||||
|             { | ||||
|                 settings = AssetDatabase.LoadAssetAtPath<FacebookSettings>(FACEBOOK_SETTINGS_PATH); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 settings = CreateInstance<FacebookSettings>(); | ||||
|                 AssetDatabase.CreateAsset(settings, FACEBOOK_SETTINGS_PATH); | ||||
|             } | ||||
| 
 | ||||
|             var so = new SerializedObject(settings); | ||||
|             SerializedProperty n; | ||||
|              | ||||
|             n = so.FindProperty("appLabels"); | ||||
|             if (n != null) | ||||
|             { | ||||
|                 n.ClearArray(); | ||||
|                 n.InsertArrayElementAtIndex(0); | ||||
|                 n.GetArrayElementAtIndex(0).stringValue = _serviceConfig.app_settings.product_name; | ||||
|             } | ||||
| 
 | ||||
|             n = so.FindProperty("appIds"); | ||||
|             if (n != null) | ||||
|             { | ||||
|                 n.ClearArray(); | ||||
|                 n.InsertArrayElementAtIndex(0); | ||||
|                 n.GetArrayElementAtIndex(0).stringValue = _serviceConfig.fb_settings.app_id; | ||||
|             } | ||||
|              | ||||
|             n = so.FindProperty("clientTokens"); | ||||
|             if (n != null) | ||||
|             { | ||||
|                 n.ClearArray(); | ||||
|                 n.InsertArrayElementAtIndex(0); | ||||
|                 n.GetArrayElementAtIndex(0).stringValue = _serviceConfig.fb_settings.client_token; | ||||
|             } | ||||
|              | ||||
|             n = so.FindProperty("androidKeystorePath"); | ||||
|             n.stringValue = ANDROID_KEYSTORE_PATH; | ||||
|              | ||||
|             so.ApplyModifiedProperties(); | ||||
|             EditorUtility.SetDirty(settings); | ||||
|             AssetDatabase.SaveAssetIfDirty(settings); | ||||
|         } | ||||
| 
 | ||||
|         private void ApplyMods() | ||||
|         { | ||||
|             PlayerSettings.applicationIdentifier = _serviceConfig.app_settings.bundle_id; // 设置包名 | ||||
| 
 | ||||
| #if UNITY_ANDROID | ||||
|             AndroidManifestMod.Apply(); | ||||
|             AndroidProjectMod.Apply(); | ||||
| #endif | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region GUI Utils | ||||
|          | ||||
| 
 | ||||
|         private void GUI_Color(Color color, Action content) | ||||
|         { | ||||
|             var c = GUI.color; | ||||
|             GUI.color = color; | ||||
|             content?.Invoke(); | ||||
|             GUI.color = c; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         private void GUI_Button(string label, Action content, Color color, GUIStyle style = null, params GUILayoutOption[] options) | ||||
|         { | ||||
|             GUI_Color(color, ()=> GUI_Button(label, content, style, options)); | ||||
|         } | ||||
|         private void GUI_Button(string label, Action content, GUIStyle style = null, params GUILayoutOption[] options) | ||||
|         { | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|             if (style != null) | ||||
|             { | ||||
|                 if (GUILayout.Button(label,style, options)) | ||||
|                 { | ||||
|                     content?.Invoke(); | ||||
|                 } | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 if (GUILayout.Button(label, options)) | ||||
|                 { | ||||
|                     content?.Invoke(); | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
|              | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Utils | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 获取Assets路径 | ||||
|         /// </summary> | ||||
|         /// <param name="filter"></param> | ||||
|         /// <returns></returns> | ||||
|         private static bool IsAssetExists(string typeName, string defaultPath) | ||||
|         { | ||||
|             bool result = false; | ||||
|             var guids = AssetDatabase.FindAssets($"t:{typeName}"); | ||||
|             string p = ""; | ||||
|             if (guids != null && guids.Length > 0) | ||||
|             { | ||||
|                 for (int i = 0; i < guids.Length; i++) | ||||
|                 { | ||||
|                     p = AssetDatabase.GUIDToAssetPath(guids[i]); | ||||
|                     if (File.Exists(p)) | ||||
|                     { | ||||
|                         if (p == defaultPath) | ||||
|                         { | ||||
|                             result = true; | ||||
|                         } | ||||
|                         else | ||||
|                         { | ||||
|                             File.Delete(p); | ||||
|                         } | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             return result; | ||||
|         } | ||||
| 
 | ||||
|         private static bool IsArrayNotEmpty(Array array) | ||||
|         { | ||||
|             if (array == null) return false; | ||||
|             if (array.Length == 0) return false; | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         private static bool IsArrayHasLength(Array array, int length) | ||||
|         { | ||||
|             if(!IsArrayNotEmpty(array)) return false; | ||||
|             return array.Length >= length; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 0a6aed96e95b747cdbb3c19c8d01b5f1 | ||||
| timeCreated: 1702786341 | ||||
|  | @ -0,0 +1,22 @@ | |||
| { | ||||
|     "name": "GuruSDK.Editor", | ||||
|     "rootNamespace": "Guru.Editor", | ||||
|     "references": [ | ||||
|         "Unity.EditorCoroutines.Editor", | ||||
|         "GuruSDK", | ||||
|         "Guru.LitJson", | ||||
|         "Guru.Runtime", | ||||
|         "MaxSdk.Scripts.IntegrationManager.Editor" | ||||
|     ], | ||||
|     "includePlatforms": [ | ||||
|         "Editor" | ||||
|     ], | ||||
|     "excludePlatforms": [], | ||||
|     "allowUnsafeCode": false, | ||||
|     "overrideReferences": false, | ||||
|     "precompiledReferences": [], | ||||
|     "autoReferenced": true, | ||||
|     "defineConstraints": [], | ||||
|     "versionDefines": [], | ||||
|     "noEngineReferences": false | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 65cafb0a78f2a474eb82c73f624745d8 | ||||
| timeCreated: 1702611049 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: c0ee5782432f84c0a8d70e660102aabe | ||||
| timeCreated: 1702610991 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 8e84534c908cf44e3bb7d315216557da | ||||
| timeCreated: 1702611028 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: e8c2747c350c2451089422bf119c2094 | ||||
| timeCreated: 1703505490 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 99b9bdd32c352412598d6d22bf5438b6 | ||||
| timeCreated: 1702628339 | ||||
|  | @ -0,0 +1,223 @@ | |||
| 
 | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|      | ||||
|      | ||||
|     public partial class GuruSDK | ||||
|     { | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 启动广告服务 | ||||
|         /// </summary> | ||||
|         public static void StartAds() | ||||
|         { | ||||
|             if (InitConfig.UseCustomConsent) | ||||
|             { | ||||
|                 Debug.Log($"{Tag} --- Call <color=orange>StartAdsWithCustomConsent</color> when you use custom consent, and pass the result (boolean) to the method."); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 // 默认的启动顺序是先启动Consent后, 根据用户回调的结果来启动广告 | ||||
|                 Instance.StartConsentFlow(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 使用自定义的Consent, 获取用户授权后, 调用此方法 | ||||
|         /// </summary> | ||||
|         /// <param name="userAllow"></param> | ||||
|         public static void StartAdsWithCustomConsent(bool userAllow = true) | ||||
|         { | ||||
|             if (userAllow) | ||||
|             { | ||||
|                 StartAdService(); | ||||
|             } | ||||
|             else | ||||
|             { | ||||
|                 Debug.Log($"{Tag} --- User refuse to provide ads Id, Ads Service will be cancelled"); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #region Guru Consent | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 启动Consent流程 | ||||
|         /// </summary> | ||||
|         private void StartConsentFlow() | ||||
|         { | ||||
|             LogI($"StartConsentFlow"); | ||||
|             GuruConsent.StartConsent(OnConsentOver); | ||||
|         } | ||||
| 
 | ||||
|         private void OnConsentOver(int code) | ||||
|         { | ||||
|             Callbacks.ConsentFlow._onConsentResult?.Invoke(code); | ||||
|             switch(code) | ||||
|             { | ||||
|                 case GuruConsent.StatusCode.OBTAINED: | ||||
|                 case GuruConsent.StatusCode.NOT_AVAILABLE: | ||||
|                     // 已获取授权, 或者地区不可用 | ||||
| #if UNITY_IOS | ||||
|                     CheckATTStatus(); | ||||
| #else | ||||
|                     StartAdService(); | ||||
| #endif | ||||
|                     break; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| #if UNITY_IOS | ||||
|          /// <summary> | ||||
|         /// iOS 平台检查 ATT 状态 | ||||
|         /// </summary> | ||||
|         private void CheckATTStatus() | ||||
|         { | ||||
|             AttManager.Instance.CheckATTStatus(OnATTStatus); | ||||
|         } | ||||
| #endif | ||||
|          | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Ad Services | ||||
| 
 | ||||
|         private static bool _initAdsCompleted = false; | ||||
|          | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 启动广告服务 | ||||
|         /// </summary> | ||||
|         public static void StartAdService() | ||||
|         { | ||||
|             LogI($"StartAdService"); | ||||
|             ADService.Instance.StartService(OnAdsInitComplete,  | ||||
|                 InitConfig.AutoLoadWhenAdsReady, IsDebugMode); | ||||
|              | ||||
|             //--------- Callbacks ----------- | ||||
|             ADService.OnInterstitialLoaded = OnInterstitialLoaded; | ||||
|             ADService.OnInterstitialFailed = OnInterstitialFailed; | ||||
|             ADService.OnRewardLoaded = OnRewardLoaded; | ||||
|             ADService.OnRewardFailed = OnRewardFailed; | ||||
|         } | ||||
| 
 | ||||
|         private static void OnInterstitialLoaded()  | ||||
|             => Callbacks.Ads._onInterstitialADLoaded?.Invoke(); | ||||
|         private static void OnInterstitialFailed() | ||||
|             => Callbacks.Ads._onInterstitialADFailed?.Invoke(); | ||||
|         private static void OnRewardLoaded() | ||||
|             => Callbacks.Ads._onRewardedADLoaded?.Invoke();  | ||||
|         private static void OnRewardFailed() | ||||
|             => Callbacks.Ads._onRewardADFailed?.Invoke(); | ||||
| 
 | ||||
|         private static void OnAdsInitComplete() | ||||
|         { | ||||
|             _initAdsCompleted = true; | ||||
|             Callbacks.Ads._onAdsInitComplete?.Invoke(); | ||||
|         } | ||||
| 
 | ||||
|         private static bool CheckAdsReady() | ||||
|         { | ||||
|             if (!_initAdsCompleted) | ||||
|             { | ||||
|                 LogE("Ads is not ready. Call <GuruSDk.StartAdService> first."); | ||||
|                 return false; | ||||
|             } | ||||
|             return true; | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 显示Banner广告 | ||||
|         /// </summary> | ||||
|         /// <param name="placement"></param> | ||||
|         public static void ShowBanner(string placement = "") | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             ADService.Instance.ShowBanner(placement); | ||||
|         } | ||||
|         /// <summary> | ||||
|         /// 隐藏Banner广告 | ||||
|         /// </summary> | ||||
|         public static void HideBanner() | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             ADService.Instance.HideBanner(); | ||||
|         } | ||||
| 
 | ||||
|         public static void LoadInterstitialAd() | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             ADService.Instance.RequestInterstitialAD(); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 显示插屏广告 | ||||
|         /// </summary> | ||||
|         /// <param name="placement"></param> | ||||
|         /// <param name="onDismissed"></param> | ||||
|         public static void ShowInterstitialAd(string placement = "", Action onDismissed = null) | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             if (!ADService.Instance.IsInterstitialADReady()) | ||||
|             { | ||||
|                 LogE("Interstitial is not ready. Call <GuruSDk.ShowInterstitialAd> again."); | ||||
|                 LoadInterstitialAd(); | ||||
|                 return; | ||||
|             } | ||||
|             ADService.Instance.ShowInterstitialAD(placement, onDismissed); | ||||
|         } | ||||
| 
 | ||||
|         public static void LoadRewardAd() | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             ADService.Instance.RequestRewardedAD(); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 显示激励视频广告 | ||||
|         /// </summary> | ||||
|         /// <param name="placement"></param> | ||||
|         /// <param name="onRewarded"></param> | ||||
|         /// <param name="onFailed"></param> | ||||
|         public static void ShowRewardAd(string placement = "", Action onRewarded = null, Action<string> onFailed = null) | ||||
|         { | ||||
|             if (!CheckAdsReady()) return; | ||||
|             if (!ADService.Instance.IsRewardedADReady()) | ||||
|             { | ||||
|                 LogE("RewardAd is not ready. Call <GuruSDk.LoadRewardAd> again."); | ||||
|                 LoadRewardAd(); | ||||
|                 return; | ||||
|             } | ||||
|             ADService.Instance.ShowRewardedAD(placement, onRewarded, onFailed); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region MaxServices | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 显示Max调试菜单 | ||||
|         /// </summary> | ||||
|         public static void ShowMaxDebugPanel() | ||||
|         { | ||||
| #if UNITY_EDITOR | ||||
| 
 | ||||
|             LogI($"Can not show Max Debug Panel in Editor, skipped."); | ||||
|             return; | ||||
| #endif | ||||
|             if (!ADService.Instance.IsInitialized) | ||||
|             { | ||||
|                 LogI($"ADService is not initialized, call <GuruSDK.StartAds> first."); | ||||
|                 return; | ||||
|             } | ||||
|             ADService.Instance.ShowMaxDebugPanel(); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: d1320ee3985cd4265906c63a00fd12d4 | ||||
| timeCreated: 1702628352 | ||||
|  | @ -0,0 +1,216 @@ | |||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|      | ||||
|      | ||||
|     /// <summary> | ||||
|     /// 打点管理 | ||||
|     /// </summary> | ||||
|     public partial class GuruSDK | ||||
|     { | ||||
|         //----------------- 关卡开始类型 --------------------- | ||||
|         public const string EventLevelStartModePlay = "play"; | ||||
|         public const string EventLevelStartModeReplay = "replay"; | ||||
|         public const string EventLevelStartModeContinue= "continue"; | ||||
|          | ||||
|         //----------------- 关卡结束类型 --------------------- | ||||
|         public const string EventLevelEndSuccess = "success"; | ||||
|         public const string EventLevelEndFail = "fail"; | ||||
|         public const string EventLevelEndExit = "exit"; | ||||
|         public const string EventLevelEndTimeout = "timeout"; | ||||
| 
 | ||||
|         #region 通用接口 | ||||
|         /// <summary> | ||||
|         /// 自定义事件打点 | ||||
|         /// </summary> | ||||
|         /// <param name="eventName"></param> | ||||
|         /// <param name="data"></param> | ||||
|         public static void LogEvent(string eventName, Dictionary<string, dynamic> data = null) | ||||
|             => Analytics.Track(eventName, data); | ||||
| 
 | ||||
|         public static void SetScreen(string screen, string extra = "")  | ||||
|             => Analytics.SetCurrentScreen(screen, extra); | ||||
|          | ||||
|          | ||||
|          | ||||
|         #endregion | ||||
|          | ||||
|         #region 游戏打点 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 游戏启动打点 | ||||
|         /// </summary> | ||||
|         /// <param name="level"></param> | ||||
|         /// <param name="levelName"></param> | ||||
|         /// <param name="levelCategory"></param> | ||||
|         /// <param name="levelID"></param> | ||||
|         /// <param name="startType"></param> | ||||
|         /// <param name="isReplay"></param> | ||||
|         public static void LogLevelStart(int level, string startType = EventLevelStartModePlay,  | ||||
|             string levelCategory = "main", string levelName = "", string levelID = "", | ||||
|             bool isReplay = false) | ||||
|         { | ||||
|             Analytics.LogLevelStart(level, levelName, levelCategory, levelID, startType, isReplay); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 游戏点击 Continue 重开始游戏 | ||||
|         /// </summary> | ||||
|         /// <param name="level"></param> | ||||
|         /// <param name="levelCategory"></param> | ||||
|         /// <param name="levelName"></param> | ||||
|         /// <param name="levelID"></param> | ||||
|         public static void LogLevelContinue(int level, string levelCategory = "main", | ||||
|             string levelName = "", string levelID = "") | ||||
|         { | ||||
|             LogLevelStart(level, EventLevelStartModeContinue, levelCategory, levelName, levelID,  true); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 游戏点击 Continue 重开始游戏 | ||||
|         /// </summary> | ||||
|         /// <param name="level"></param> | ||||
|         /// <param name="levelCategory"></param> | ||||
|         /// <param name="levelName"></param> | ||||
|         /// <param name="levelID"></param> | ||||
|         public static void LogLevelReplay(int level, string levelCategory = "main", | ||||
|             string levelName = "", string levelID = "") | ||||
|         { | ||||
|             LogLevelStart(level, EventLevelStartModeReplay,levelCategory, levelName, levelID,  true); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 游戏胜利打点 | ||||
|         /// </summary> | ||||
|         public static void LogLevelEnd(int level,  string result = EventLevelEndSuccess, | ||||
|             string levelCategory = "main", string levelName = "", string levelID = "", | ||||
|             int? duration = null, int? step = null, int? score = null ) | ||||
|         { | ||||
|             if (InitConfig.AutoRecordFinishedLevels) | ||||
|             { | ||||
|                 if(result == EventLevelEndSuccess) Model.SuccessLevelCount++; // 自动记录关卡完成次数 | ||||
|                 Model.TotalPlayedCount++; // 自动记录关卡总次数 | ||||
| 
 | ||||
|                 Analytics.BLevel = Model.SuccessLevelCount; // 记录 BLevel | ||||
|                 Analytics.BPlay = Model.TotalPlayedCount; // 记录 BPlay | ||||
|             } | ||||
|              | ||||
|             Analytics.LogLevelEnd(level, result,  | ||||
|                 levelName, levelCategory, levelCategory, | ||||
|                 duration, step, score); | ||||
|         } | ||||
|          | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 游戏失败打点 | ||||
|         /// 需要为游戏记录详细的失败原因 | ||||
|         /// </summary> | ||||
|         public static void LogLevelFail(int level, | ||||
|             string levelCategory = "main",string levelName = "", string levelID = "", | ||||
|             int? duration = null, int? step = null, int? score = null ) | ||||
|         { | ||||
|             LogLevelEnd(level, EventLevelEndFail, levelCategory, levelName, levelID, duration, step, score); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 因退出关卡导致游戏失败 | ||||
|         /// </summary> | ||||
|         public static void LogLevelFailExit(int level, | ||||
|             string levelCategory = "main", string levelName = "", string levelID = "", | ||||
|             int? duration = null, int? step = null, int? score = null) | ||||
|         { | ||||
|             LogLevelEnd(level, EventLevelEndExit, levelCategory, levelName, levelID, duration, step, score); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 因关卡超时导致游戏失败 | ||||
|         /// </summary> | ||||
|         public static void LogLevelFailTimeout(int level, | ||||
|             string levelCategory = "main", string levelName = "", string levelID = "", | ||||
|             int? duration = null, int? step = null, int? score = null) | ||||
|         { | ||||
|             LogLevelEnd(level, EventLevelEndTimeout, levelCategory, levelName, levelID, duration, step, score); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 玩家(角色)升级事件 | ||||
|         /// </summary> | ||||
|         /// <param name="playerLevel"></param> | ||||
|         /// <param name="playerName"></param> | ||||
|         public static void LogLevelUp(int playerLevel, string playerName) | ||||
|         { | ||||
|             Analytics.LevelUp(playerLevel, playerName); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 玩家解锁成就 | ||||
|         /// </summary> | ||||
|         /// <param name="achievementName"></param> | ||||
|         public static void LogAchievement(string achievementName) | ||||
|         { | ||||
|             Analytics.UnlockAchievement(achievementName); | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|         #region 用户属性 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 设置用户属性 | ||||
|         /// </summary> | ||||
|         /// <param name="key"></param> | ||||
|         /// <param name="value"></param> | ||||
|         public static void SetUserProperty(string key, string value) | ||||
|             => Analytics.SetUserProperty(key, value); | ||||
| 
 | ||||
|         public static void SetUID(string uid) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyUserID, uid); | ||||
|         } | ||||
| 
 | ||||
|         public static void SetUserBLevel(int blevel) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyLevel, $"{blevel}"); | ||||
|         } | ||||
|          | ||||
|         public static void SetUserBPlay(int bplay) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyPlay, $"{bplay}"); | ||||
|         } | ||||
| 
 | ||||
|         public static void SetUserTotalCoins(int totalCoins) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyCoin, $"{totalCoins}");         | ||||
|         } | ||||
|          | ||||
|         public static void SetUserCoins(int coins) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyNonIAPCoin, $"{coins}");         | ||||
|         } | ||||
|          | ||||
|         public static void SetUserPaidCoins(int paidCoins) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyIAPCoin, $"{paidCoins}");         | ||||
|         } | ||||
|          | ||||
|         public static void SetUserExp(int exp) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyExp, $"{exp}");         | ||||
|         } | ||||
|          | ||||
|         public static void SetUserHp(int hp) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyHp, $"{hp}");         | ||||
|         } | ||||
| 
 | ||||
|         public static void SetUserGrade(int grade) | ||||
|         { | ||||
|             SetUserProperty(Analytics.PropertyGrade, $"{grade}");         | ||||
|         } | ||||
|          | ||||
|          | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: b2b75eb78fc3c4f148365eb7e3d89bd7 | ||||
| timeCreated: 1703308617 | ||||
|  | @ -0,0 +1,119 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using System; | ||||
|     using UnityEngine; | ||||
|      | ||||
|      | ||||
|     public partial class GuruSDK | ||||
|     { | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 回调参数类 | ||||
|         /// </summary> | ||||
|         public class Callbacks | ||||
|         { | ||||
|              | ||||
| 
 | ||||
|             /// <summary> | ||||
|             /// GDPR Consent | ||||
|             /// </summary> | ||||
|             public static class ConsentFlow | ||||
|             { | ||||
|                 /// <summary> | ||||
|                 /// 当Consent启动结束后返回状态码 | ||||
|                 /// </summary> | ||||
|                 public static event Action<int> OnConsentResult | ||||
|                 { | ||||
|                     add => _onConsentResult += value; | ||||
|                     remove => _onConsentResult -= value; | ||||
|                 } | ||||
|                 internal static Action<int> _onConsentResult; | ||||
| 
 | ||||
|                 /// <summary> | ||||
|                 /// ATT 状态返回 | ||||
|                 /// </summary> | ||||
|                 public static event Action<int> OnAttResult | ||||
|                 { | ||||
|                     add => _onAttResult += value; | ||||
|                     remove => _onAttResult -= value; | ||||
|                 } | ||||
|                 internal static Action<int> _onAttResult; | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|             /// <summary> | ||||
|             /// 广告回调 | ||||
|             /// </summary> | ||||
|             public static class Ads | ||||
|             { | ||||
|                 internal static Action _onAdsInitComplete; | ||||
|                 public static event Action OnAdsInitComplete | ||||
|                 { | ||||
|                     add => _onAdsInitComplete += value; | ||||
|                     remove => _onAdsInitComplete -= value; | ||||
|                 } | ||||
|                  | ||||
|                 internal static Action _onInterstitialADLoaded; | ||||
|                 public static event Action OnInterstitialADLoaded | ||||
|                 { | ||||
|                     add => _onInterstitialADLoaded += value; | ||||
|                     remove => _onInterstitialADLoaded -= value; | ||||
|                 } | ||||
| 
 | ||||
|                 internal static Action _onInterstitialADFailed; | ||||
|                 public static event Action OnInterstitialADFailed | ||||
|                 { | ||||
|                     add => _onInterstitialADFailed += value; | ||||
|                     remove => _onInterstitialADFailed -= value; | ||||
|                 } | ||||
| 
 | ||||
|                 internal static Action _onRewardedADLoaded; | ||||
|                 public static event Action OnRewardedADLoaded | ||||
|                 { | ||||
|                     add => _onRewardedADLoaded += value; | ||||
|                     remove => _onRewardedADLoaded -= value; | ||||
|                 } | ||||
| 
 | ||||
|                 internal static Action _onRewardADFailed; | ||||
|                 public static event Action OnRewardADFailed | ||||
|                 { | ||||
|                     add => _onRewardADFailed += value; | ||||
|                     remove => _onRewardADFailed -= value; | ||||
|                 } | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             public static class Remote | ||||
|             { | ||||
|                 internal static Action _onRemoteInitComplete; | ||||
|                 public static event Action OnRemoteInitComplete; | ||||
|                  | ||||
|                 internal static Action _onRemoteFetchComplete; | ||||
|                 public static event Action OnRemoteFetchComplete; | ||||
|             } | ||||
| 
 | ||||
| 
 | ||||
|             public static class IAP | ||||
|             { | ||||
|                 internal static Action<bool> _onIAPInitComplete; | ||||
|                 public static event Action<bool> OnIAPInitComplete | ||||
|                 { | ||||
|                     add => _onIAPInitComplete += value; | ||||
|                     remove => _onIAPInitComplete -= value; | ||||
|                 } | ||||
|                  | ||||
|                 internal static Action<string> _onPurchaseStart; | ||||
|                 public static event Action<string> OnPurchaseStart | ||||
|                 { | ||||
|                     add => _onPurchaseStart += value; | ||||
|                     remove => _onPurchaseStart -= value; | ||||
|                 } | ||||
| 
 | ||||
|             } | ||||
| 
 | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 971089341f7a64ee38f8d3f82e40f59c | ||||
| timeCreated: 1703307770 | ||||
|  | @ -0,0 +1,136 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|     using System.Linq; | ||||
|      | ||||
|      | ||||
|     public partial class GuruSDK | ||||
|     { | ||||
|         public static bool IsIAPReady = false; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 初始化IAP 功能 | ||||
|         /// </summary> | ||||
|         public static void InitIAP(byte[] googleKey, byte[] appleRootCerts) | ||||
|         { | ||||
|             GuruIAP.Instance.OnInitResult += OnIAPInitResult; | ||||
|             GuruIAP.Instance.OnRestored += OnRestored; | ||||
|             GuruIAP.Instance.OnBuyStart += OnBuyStart; | ||||
|             GuruIAP.Instance.OnBuyEnd += OnBuyEnd; | ||||
|              | ||||
|             GuruIAP.Instance.InitWithKeys(googleKey, appleRootCerts, IsDebugMode); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 初始化结果 | ||||
|         /// </summary> | ||||
|         /// <param name="success"></param> | ||||
|         private static void OnIAPInitResult(bool success) | ||||
|         { | ||||
|             LogI($"IAP init result: {success}"); | ||||
|              | ||||
|             IsIAPReady = success; | ||||
|             Callbacks.IAP._onIAPInitComplete?.Invoke(success); | ||||
|         } | ||||
| 
 | ||||
|         private static bool CheckIAPReady() | ||||
|         { | ||||
|             if (!IsIAPReady) | ||||
|             { | ||||
|                 LogE("IAP is not ready, call <GuruSDK.InitIAP> first."); | ||||
|                 return false; | ||||
|             } | ||||
| 
 | ||||
|             return true; | ||||
|         } | ||||
|          | ||||
|         #region Purchase | ||||
| 
 | ||||
|         public static ProductSetting GetProductSettingById(string productId) | ||||
|         { | ||||
|             var products = GuruSettings.Instance.Products; | ||||
|             if (products != null && products.Length > 0) | ||||
|             { | ||||
|                 return products.FirstOrDefault(p => p.ProductId == productId);    | ||||
|             } | ||||
|             return null; | ||||
|         } | ||||
|          | ||||
|         private static Action<string, bool> _onPurchaseCallback; | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 购买商品, 通过商品Name | ||||
|         /// </summary> | ||||
|         /// <param name="productId"></param> | ||||
|         /// <param name="purchaseCallback"></param> | ||||
|         public static void Purchase(string productName, Action<string, bool> purchaseCallback = null) | ||||
|         { | ||||
|             if (CheckIAPReady()) | ||||
|             { | ||||
|                 _onPurchaseCallback = purchaseCallback; | ||||
|                 GuruIAP.Instance.Buy(productName); | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 购买商品, 通过商品ID | ||||
|         /// </summary> | ||||
|         /// <param name="productId"></param> | ||||
|         /// <param name="purchaseCallback"></param> | ||||
|         public static bool PurchaseById(string productId, Action<string, bool> purchaseCallback = null) | ||||
|         { | ||||
|             var productName = GetProductSettingById(productId)?.ProductName ?? ""; | ||||
|              | ||||
|             if (CheckIAPReady() && !string.IsNullOrEmpty(productName)) | ||||
|             { | ||||
|                 Purchase(productName, purchaseCallback); | ||||
|                 return true; | ||||
|             } | ||||
|             return false; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 支付回调 | ||||
|         /// </summary> | ||||
|         /// <param name="productId"></param> | ||||
|         /// <param name="success"></param> | ||||
|         private static void OnBuyEnd(string productId, bool success) | ||||
|         { | ||||
|             _onPurchaseCallback?.Invoke(productId, success); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         private static void OnBuyStart(string productId) | ||||
|         { | ||||
|             Callbacks.IAP._onPurchaseStart?.Invoke(productId); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|         #region Restore Purchase | ||||
| 
 | ||||
|         private static Action<bool> _onRestored; | ||||
|         /// <summary> | ||||
|         /// 恢复购买 | ||||
|         /// </summary> | ||||
|         /// <param name="restoreCallback"></param> | ||||
|         public static void Restore(Action<bool> restoreCallback) | ||||
|         { | ||||
|             if (CheckIAPReady()) | ||||
|             { | ||||
|                 _onRestored = restoreCallback; | ||||
|                 GuruIAP.Instance.Restore(); | ||||
|             } | ||||
|         } | ||||
|         private static void OnRestored(bool success) | ||||
|         { | ||||
|             _onRestored?.Invoke(success); | ||||
|         } | ||||
|          | ||||
|         #endregion | ||||
| 
 | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 2613bac8a776048ac9fd924c6dc7244f | ||||
| timeCreated: 1703320826 | ||||
|  | @ -0,0 +1,175 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|      | ||||
|     public partial class GuruSDK: MonoBehaviour | ||||
|     { | ||||
|         public const string Version = "0.1.0"; | ||||
|         public static readonly string Tag = "[Guru]"; | ||||
|          | ||||
|         private static GuruSDK _instance; | ||||
|         /// <summary> | ||||
|         /// 单利引用 | ||||
|         /// </summary> | ||||
|         public static GuruSDK Instance | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if(null == _instance) | ||||
|                 { | ||||
|                     _instance = CreateInstance(); | ||||
|                 } | ||||
|                 return _instance; | ||||
|             } | ||||
|              | ||||
|         } | ||||
| 
 | ||||
|         private GuruSDKInitConfig _initConfig; | ||||
|         private Action<bool> _onCompleteCallback; | ||||
| 
 | ||||
|         private static GuruSDKModel _model; | ||||
| 
 | ||||
|         internal static GuruSDKInitConfig InitConfig => Instance._initConfig; | ||||
|         internal static GuruSDKModel Model => GuruSDKModel.Instance; | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// Debug Mode | ||||
|         /// </summary> | ||||
|         public static bool IsDebugMode | ||||
|         { | ||||
|             get | ||||
|             { | ||||
| #if UNITY_EDITOR || DEBUG | ||||
|                 return true; | ||||
| #endif | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|          | ||||
|         #region 初始化 | ||||
| 
 | ||||
| 
 | ||||
|         private static GuruSDK CreateInstance() | ||||
|         { | ||||
|             var go = new GameObject(nameof(GuruSDK)); | ||||
|             DontDestroyOnLoad(go); | ||||
|             _instance = go.AddComponent<GuruSDK>(); | ||||
|             return _instance; | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         public static void Init(Action<bool> onComplete) | ||||
|         { | ||||
|             Init(GuruSDKInitConfig.Build(), onComplete); | ||||
|         } | ||||
|          | ||||
|         public static void Init(GuruSDKInitConfig config, Action<bool> onComplete) | ||||
|         { | ||||
|             LogI($"---- Guru SDK init ----"); | ||||
|             LogI(config.ToString()); | ||||
|             Instance.StartWithConfig(config, onComplete); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 启动SDK | ||||
|         /// </summary> | ||||
|         /// <param name="config"></param> | ||||
|         /// <param name="onComplete"></param> | ||||
|         private void StartWithConfig(GuruSDKInitConfig config, Action<bool> onComplete) | ||||
|         { | ||||
|             Model.PropBLevel.OnValueChanged += OnBLevelChanged; | ||||
|             Model.PropBPlay.OnValueChanged += OnBPlayChanged; | ||||
|              | ||||
|             _initConfig = config; | ||||
|             _onCompleteCallback = onComplete; | ||||
|              | ||||
|             //---------- Start Firebase ------------ | ||||
|             FirebaseUtil.InitFirebase(OnFirebaseReady); | ||||
|             FirebaseUtil.OnFetchRemoteSuccess += OnFetchRemoteSuccess; | ||||
|             //---------- Start Facebook ------------ | ||||
|             FBService.Instance.StartService(); | ||||
|         } | ||||
| 
 | ||||
|         private void OnFetchRemoteSuccess() | ||||
|         { | ||||
|             Callbacks.Remote._onRemoteFetchComplete?.Invoke(); | ||||
|         } | ||||
| 
 | ||||
|         /// <summary> | ||||
|         /// 开始各种组件初始化 | ||||
|         /// </summary> | ||||
|         private void OnFirebaseReady() | ||||
|         { | ||||
|             LogI($"--- #1 SDK Init complete ---"); | ||||
|             if (InitConfig.IAPEnabled) | ||||
|             { | ||||
|                 LogI($"--- #2 Init IAP ---"); | ||||
|                 InitIAP(_initConfig.GoogleKeys, _initConfig.AppleRootCerts); // 初始化IAP | ||||
|             } | ||||
| 
 | ||||
|             if (!InitConfig.UseCustomConsent) | ||||
|             { | ||||
|                 LogI($"--- #3 Start Consent Flow ---"); | ||||
|                 StartConsentFlow(); | ||||
|             } | ||||
| 
 | ||||
|             //TODO: 开始Remote初始化  | ||||
|              | ||||
|             if(!string.IsNullOrEmpty(IPMConfig.IPM_UID)) SetUID(IPMConfig.IPM_UID); | ||||
|              | ||||
|             _onCompleteCallback?.Invoke(true); | ||||
|         } | ||||
| 
 | ||||
|         private void OnBLevelChanged(int blevel) | ||||
|         { | ||||
|             SetUserBLevel(blevel); | ||||
|         } | ||||
| 
 | ||||
|         private void OnBPlayChanged(int bplay) | ||||
|         { | ||||
|             SetUserBPlay(bplay); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Misc | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 打开页面 | ||||
|         /// </summary> | ||||
|         /// <param name="url"></param> | ||||
|         public static void OpenURL(string url) | ||||
|         { | ||||
|             GuruWebview.OpenPage(url); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Logging | ||||
|          | ||||
|          | ||||
|         public static void LogI(object message) | ||||
|         { | ||||
|             Debug.Log($"{Tag} {message}"); | ||||
|         } | ||||
|          | ||||
|         public static void LogW(object message) | ||||
|         { | ||||
|             Debug.LogWarning($"{Tag} {message}"); | ||||
|         } | ||||
|          | ||||
|         public static void LogE(object message) | ||||
|         { | ||||
|             Debug.LogError($"{Tag} {message}"); | ||||
|         } | ||||
| 
 | ||||
|         #endregion | ||||
|          | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 62635518506334610aeaf54c9c29fe75 | ||||
| timeCreated: 1703035168 | ||||
|  | @ -0,0 +1,97 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using System.Collections.Generic; | ||||
|     using System.Text; | ||||
|     /// <summary> | ||||
|     /// 启动参数配置 | ||||
|     /// </summary> | ||||
|     public partial class GuruSDKInitConfig | ||||
|     { | ||||
|         /// <summary> | ||||
|         /// 使用自定义的ConsentFlow启动流程 | ||||
|         /// </summary> | ||||
|         public bool UseCustomConsent = false; | ||||
|         /// <summary> | ||||
|         /// SDK初始化完成后自动加载广告 | ||||
|         /// </summary> | ||||
|         public bool AutoLoadWhenAdsReady = true; | ||||
|         /// <summary> | ||||
|         /// 使用IAP支付插件功能 | ||||
|         /// </summary> | ||||
|         public bool IAPEnabled = true; | ||||
|         /// <summary> | ||||
|         /// 自动记录完成的关卡 | ||||
|         /// </summary> | ||||
|         public bool AutoRecordFinishedLevels = true; | ||||
|         /// <summary> | ||||
|         /// 显示Debug日志 | ||||
|         /// </summary> | ||||
|         public bool ShowDebugLog = false; | ||||
|         /// <summary> | ||||
|         /// 运控参数的默认配置 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public Dictionary<string, object> DefaultRemoteData = new Dictionary<string, object>(); | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 支付初始化Keys | ||||
|         /// </summary> | ||||
|         public byte[] GoogleKeys; | ||||
|         public byte[] AppleRootCerts; | ||||
|          | ||||
|         #region Initialization | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 构建启动配置 | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         public static GuruSDKInitConfig Build( | ||||
|             bool useCustomConsent = false,  | ||||
|             bool autoLoadAds = true,  | ||||
|             bool iapEnabled = true,  | ||||
|             bool autoRecordFinishedLevels = true,  | ||||
|             bool showDebugLog = false, | ||||
|             Dictionary<string, object> defaultRemoteData = null, | ||||
|             byte[] googleKeys = null, | ||||
|             byte[] appleRootCerts = null) | ||||
|         { | ||||
|             // 创建启动用参数 | ||||
|             GuruSDKInitConfig config = new GuruSDKInitConfig() | ||||
|             { | ||||
|                 UseCustomConsent = useCustomConsent, | ||||
|                 AutoLoadWhenAdsReady = autoLoadAds, | ||||
|                 IAPEnabled = iapEnabled, | ||||
|                 AutoRecordFinishedLevels = autoRecordFinishedLevels, | ||||
|                 ShowDebugLog = showDebugLog, | ||||
|                 GoogleKeys = googleKeys, | ||||
|                 AppleRootCerts = appleRootCerts, | ||||
|                 DefaultRemoteData = defaultRemoteData ?? new Dictionary<string, object>(), | ||||
|             }; | ||||
| #if UNITY_EDITOR | ||||
|             config.ShowDebugLog = true; | ||||
| #endif | ||||
|             return config; | ||||
|         } | ||||
|          | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region Print | ||||
| 
 | ||||
|         public override string ToString() | ||||
|         { | ||||
|             StringBuilder sb = new StringBuilder(); | ||||
|             sb.AppendLine($"------- Custom init Config -------"); | ||||
|             sb.AppendLine($"\tUseCustomConsent: {UseCustomConsent}"); | ||||
|             sb.AppendLine($"\tAutoLoadWhenAdsReady: {AutoLoadWhenAdsReady}"); | ||||
|             sb.AppendLine($"\tIAPEnabled: {IAPEnabled}"); | ||||
|             sb.AppendLine($"\tShowDebugLog: {ShowDebugLog}"); | ||||
|             sb.AppendLine($"------- Custom init Config -------"); | ||||
|             return sb.ToString(); | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: e6c57dd4792204f5f9b778eb7e7cb920 | ||||
| timeCreated: 1703039335 | ||||
|  | @ -0,0 +1,94 @@ | |||
| using System; | ||||
| using System.Collections.Generic; | ||||
| using UnityEngine.Serialization; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|      | ||||
|     [Serializable] | ||||
|     public class GuruServiceConfig | ||||
|     { | ||||
|         public string version; | ||||
|         public GuruAppSettings app_settings; | ||||
|         public GuruAdjustSettings adjust_settings; | ||||
|         public GuruFbSettings fb_settings; | ||||
|         public GuruAdSettings ad_settings; | ||||
|         public string[] products; | ||||
|          | ||||
|         //-------------------------------- 配置检测 -------------------------------- | ||||
|         public bool IsIAPEnabled() => products != null && products.Length > 0; | ||||
| 
 | ||||
|         public bool IsAmazonAndroidEnabled() => ad_settings != null &&  | ||||
|                                                 ad_settings.amazon_ids_android != null && | ||||
|                                                 ad_settings.amazon_ids_android.Length > 0; | ||||
|         public bool IsAmazonIOSEnabled() => ad_settings != null &&  | ||||
|                                                 ad_settings.amazon_ids_ios != null && | ||||
|                                                 ad_settings.amazon_ids_ios.Length > 0; | ||||
|         public bool IsPubmaticAndroidEnabled() => ad_settings != null &&  | ||||
|                                             ad_settings.pubmatic_ids_android != null && | ||||
|                                             ad_settings.pubmatic_ids_android.Length > 0; | ||||
|         public bool IsPubmaticIOSEnabled() => ad_settings != null &&  | ||||
|                                                   ad_settings.pubmatic_ids_ios != null && | ||||
|                                                   ad_settings.pubmatic_ids_ios.Length > 0; | ||||
|         public bool IsMolocoAndroidEnabled() => ad_settings != null &&  | ||||
|                                                   ad_settings.moloco_ids_android != null && | ||||
|                                                   ad_settings.moloco_ids_android.Length > 0; | ||||
|         public bool IsMolocoIOSEnabled() => ad_settings != null &&  | ||||
|                                                 ad_settings.moloco_ids_ios != null && | ||||
|                                                 ad_settings.moloco_ids_ios.Length > 0; | ||||
|         //-------------------------------- 配置检测 -------------------------------- | ||||
|          | ||||
|          | ||||
|     } | ||||
|      | ||||
|     [Serializable]     | ||||
|     public class GuruAppSettings | ||||
|     { | ||||
|         public string app_id; | ||||
|         public string product_name; | ||||
|         public string bundle_id; | ||||
|         public string support_email; | ||||
|         public string privacy_url; | ||||
|         public string terms_url; | ||||
|         public string android_store; | ||||
|         public string ios_store; | ||||
|         public int token_vaild_time = 604800; | ||||
|         public int level_end_success_num = 50; | ||||
|         public bool enable_firebase = true; | ||||
|         public bool enable_facebook = true; | ||||
|         public bool enable_adjust = true; | ||||
|         public bool enable_iap = false; | ||||
|     } | ||||
|      | ||||
|     [Serializable] | ||||
|     public class GuruAdjustSettings | ||||
|     { | ||||
|         public string[] app_token; | ||||
|         public string[] events; | ||||
|     } | ||||
|      | ||||
|     [Serializable] | ||||
|     public class GuruFbSettings | ||||
|     { | ||||
|         public string app_id; | ||||
|         public string client_token; | ||||
|     } | ||||
| 
 | ||||
|     [Serializable] | ||||
|     public class GuruAdSettings | ||||
|     { | ||||
|         public string sdk_key; | ||||
|         public string[] admob_app_id; | ||||
|         public string[] max_ids_android; | ||||
|         public string[] max_ids_ios; | ||||
|         public string[] amazon_ids_android; | ||||
|         public string[] amazon_ids_ios; | ||||
|         public string[] pubmatic_ids_android; | ||||
|         public string[] pubmatic_ids_ios; | ||||
|         public string[] moloco_ids_android; | ||||
|         public string[] moloco_ids_ios; | ||||
|     } | ||||
| 
 | ||||
|      | ||||
|      | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 5c9728047bb1049639340975b4e8d7ee | ||||
| timeCreated: 1702861449 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 2b0ce7d06a8234e3f9a0eb466c38f041 | ||||
| timeCreated: 1702627775 | ||||
|  | @ -0,0 +1,20 @@ | |||
| namespace Guru | ||||
| { | ||||
|     internal class GuruIAP: IAPServiceBase<GuruIAP> | ||||
|     { | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 获取BLevel | ||||
|         /// </summary> | ||||
|         /// <returns></returns> | ||||
|         protected override int GetBLevel() => GuruSDKModel.Instance.SuccessLevelCount; // BLevel | ||||
| 
 | ||||
|         protected override void OnPurchaseOver(bool success, string productName) | ||||
|         { | ||||
|             if (success) | ||||
|             { | ||||
|                 GuruSDKModel.Instance.PurchasedCount++; // 记录成功购买次数 | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: f22899a5bf889441fba95e634696a74b | ||||
| timeCreated: 1703320926 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 2093caa07830a41d5958de2faf589f13 | ||||
| timeCreated: 1703321414 | ||||
|  | @ -0,0 +1,38 @@ | |||
| namespace Guru | ||||
| { | ||||
|     using UnityEngine; | ||||
|     using System; | ||||
|      | ||||
|     internal class BindableProperty<T> | ||||
|     { | ||||
|         private T _value; | ||||
| 
 | ||||
|         public T Value | ||||
|         { | ||||
|             get => _value; | ||||
|             set | ||||
|             { | ||||
|                 _value = value; | ||||
|                 OnValueChanged?.Invoke(value); | ||||
|             } | ||||
|         } | ||||
|         public event Action<T> OnValueChanged; | ||||
|          | ||||
|          | ||||
|         public BindableProperty()  | ||||
|         { | ||||
|              | ||||
|         } | ||||
| 
 | ||||
|         public BindableProperty(Action<T> onChanged) | ||||
|         { | ||||
|             OnValueChanged = onChanged; | ||||
|         } | ||||
|          | ||||
|         public BindableProperty(T initValue, Action<T> onChanged) | ||||
|         { | ||||
|             _value = initValue; | ||||
|             OnValueChanged = onChanged; | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: cc7bbb7d0d6ed42d7985198f9cfc3cb0 | ||||
| timeCreated: 1703323782 | ||||
|  | @ -0,0 +1,171 @@ | |||
| using System; | ||||
| using UnityEngine; | ||||
| using UnityEngine.Serialization; | ||||
| 
 | ||||
| namespace Guru | ||||
| { | ||||
|     [Serializable] | ||||
|     internal class GuruSDKModel | ||||
|     { | ||||
|         private static GuruSDKModel _instance; | ||||
|         public static GuruSDKModel Instance | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if (null == _instance) _instance = Load(); | ||||
|                 return _instance; | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         //-------------- data --------------- | ||||
|         public int b_level = 0; | ||||
|         public int b_play = 0; | ||||
|         public int buy_count = 0; | ||||
|         //-------------- data --------------- | ||||
| 
 | ||||
|         private float _lastSavedTime = 0; | ||||
|          | ||||
|         public int SuccessLevelCount | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if(_successLevel == null) InitProperties(); | ||||
|                 return _successLevel.Value; | ||||
|             } | ||||
|             set => _successLevel.Value = value; | ||||
|         } | ||||
| 
 | ||||
|         public int TotalPlayedCount | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if(_totalPlayed == null) InitProperties(); | ||||
|                 return _totalPlayed.Value; | ||||
|             } | ||||
|             set => _totalPlayed.Value = value; | ||||
|         } | ||||
| 
 | ||||
|         public int PurchasedCount | ||||
|         { | ||||
|             get | ||||
|             { | ||||
|                 if(_purchasedCount == null) InitProperties(); | ||||
|                 return _purchasedCount.Value; | ||||
|             } | ||||
|             set => _purchasedCount.Value = value; | ||||
|         } | ||||
| 
 | ||||
|         public bool IsIAPUser => PurchasedCount > 0; | ||||
| 
 | ||||
|          | ||||
|         private BindableProperty<int> _successLevel; | ||||
|         private BindableProperty<int> _totalPlayed; | ||||
|         private BindableProperty<int> _purchasedCount; | ||||
|          | ||||
|         public BindableProperty<int> PropBLevel => _successLevel; | ||||
|         public BindableProperty<int> PropBPlay => _totalPlayed; | ||||
|         public BindableProperty<int> PropBuyCount => _purchasedCount; | ||||
| 
 | ||||
| 
 | ||||
|         #region 初始化 | ||||
| 
 | ||||
|         private const float SaveInterval = 3; | ||||
|         private const string SaveKey = "com.guru.sdk.model.save"; | ||||
|         public static GuruSDKModel Load() | ||||
|         { | ||||
|             GuruSDKModel model = null; | ||||
|             if (PlayerPrefs.HasKey(SaveKey)) | ||||
|             { | ||||
|                 var json = PlayerPrefs.GetString(SaveKey, ""); | ||||
|                 if (!string.IsNullOrEmpty(json)) | ||||
|                 { | ||||
|                     try | ||||
|                     { | ||||
|                         model =  JsonUtility.FromJson<GuruSDKModel>(json); | ||||
|                     } | ||||
|                     catch (Exception e) | ||||
|                     { | ||||
|                         Debug.LogError(e); | ||||
|                     } | ||||
|                 } | ||||
|             } | ||||
|             if(model == null) model = new GuruSDKModel(); | ||||
|             model.InitProperties(); | ||||
|             return model; | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 保存至数据 | ||||
|         /// </summary> | ||||
|         private void SaveToPlayerPrefs() | ||||
|         { | ||||
|             var json = JsonUtility.ToJson(this); | ||||
|             PlayerPrefs.SetString(SaveKey, json); | ||||
|         } | ||||
| 
 | ||||
|         public void InitProperties() | ||||
|         { | ||||
|             _successLevel = new BindableProperty<int>(b_level, OnLevelChanged); | ||||
|             _totalPlayed = new BindableProperty<int>(b_play, OnPlayedChanged); | ||||
|             _purchasedCount = new BindableProperty<int>(buy_count, OnPurchasedNumChanged); | ||||
|         } | ||||
|          | ||||
|         /// <summary> | ||||
|         /// 保存数据 | ||||
|         /// </summary> | ||||
|         /// <param name="force"></param> | ||||
|         public void Save(bool force = false) | ||||
|         { | ||||
|             bool save = force || (Time.realtimeSinceStartup - _lastSavedTime>= SaveInterval); | ||||
|             if (save) | ||||
|             { | ||||
|                 _lastSavedTime = Time.realtimeSinceStartup; | ||||
|                 SaveToPlayerPrefs(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
| 
 | ||||
|         #endregion | ||||
| 
 | ||||
|         #region 数据绑定变化 | ||||
|         private void OnLevelChanged(int value) | ||||
|         { | ||||
|             b_level = value; | ||||
|             Save(); | ||||
|         } | ||||
|         private void OnPlayedChanged(int value) | ||||
|         { | ||||
|             b_play = value; | ||||
|             Save(); | ||||
|         } | ||||
| 
 | ||||
|         private void OnPurchasedNumChanged(int value) | ||||
|         { | ||||
|             buy_count = value; | ||||
|             Save(); | ||||
|         } | ||||
|         #endregion | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|          | ||||
| 
 | ||||
| 
 | ||||
|         | ||||
| 
 | ||||
| 
 | ||||
|     } | ||||
|      | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 9d518492c434042c6aeb20ce679df8ab | ||||
| timeCreated: 1703321428 | ||||
|  | @ -0,0 +1,19 @@ | |||
| { | ||||
|     "name": "GuruSDK", | ||||
|     "rootNamespace": "Guru", | ||||
|     "references": [ | ||||
|         "Guru.Runtime", | ||||
|         "UnityEngine.Purchasing.Security", | ||||
|         "UnityEngine.Purchasing.SecurityStub", | ||||
|         "UnityEngine.Purchasing.SecurityCore" | ||||
|     ], | ||||
|     "includePlatforms": [], | ||||
|     "excludePlatforms": [], | ||||
|     "allowUnsafeCode": false, | ||||
|     "overrideReferences": false, | ||||
|     "precompiledReferences": [], | ||||
|     "autoReferenced": true, | ||||
|     "defineConstraints": [], | ||||
|     "versionDefines": [], | ||||
|     "noEngineReferences": false | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 85fac0454e8c64a0da25f1f632acaa75 | ||||
| timeCreated: 1702611014 | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: fc679813f31644f20b79c6f24939c6a9 | ||||
| timeCreated: 1702611035 | ||||
|  | @ -0,0 +1,5 @@ | |||
| <linker> | ||||
|     <assembly fullname="GuruSDK"> | ||||
|         <namespace fullname="Guru" preserve="all"/> | ||||
|     </assembly> | ||||
| </linker> | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 33d446758bba24852bac2e3d9c6bf6fc | ||||
| timeCreated: 1703388178 | ||||
|  | @ -0,0 +1,15 @@ | |||
| { | ||||
|   "name": "com.guru.unity.sdk", | ||||
|   "displayName": "Guru SDK", | ||||
|   "version": "0.0.1", | ||||
|   "description": "Guru SDK for unity project", | ||||
|   "unity": "2020.3", | ||||
|   "author":{ | ||||
|     "name": "Guru Fungames Studio" | ||||
|   }, | ||||
|   "license": "MIT", | ||||
|   "category": "Game,Tool,Development", | ||||
|   "dependencies": { | ||||
|     "com.guru.unity.sdk.core": "git@github.com:castbox/upm-guru-sdk-core-proto.git" | ||||
|   } | ||||
| } | ||||
|  | @ -0,0 +1,3 @@ | |||
| fileFormatVersion: 2 | ||||
| guid: 2e68608e12de34fa69d2e96e7dcb8892 | ||||
| timeCreated: 1702610734 | ||||
		Loading…
	
		Reference in New Issue