init commit

feature/item_system
胡宇飞 2023-12-26 11:40:48 +08:00
commit bb1a4b8cce
64 changed files with 2900 additions and 0 deletions

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
*.DS_Store

3
Editor.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9bb2904375c2a46eb90e2a3cace489a0
timeCreated: 1702610996

3
Editor/GuruManager.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: df5ee84bbb0c0495eb6f89444802ffd9
timeCreated: 1703231056

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 44aa37ed74dd4407a9d04a07ccf97247
timeCreated: 1702611095

View File

@ -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);
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 043619bc8571240f6b8926c2ccffbd29
timeCreated: 1702877769

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eec1c72fa3d0c493b9b30091a81043ee
timeCreated: 1703413024

View File

@ -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>

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ad463c22214a24eecba0c3d3428cd2bc
timeCreated: 1703413179

View File

@ -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**

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 91158a71185444f2798701c44312902f
timeCreated: 1703468454

View File

@ -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**

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 5ca7eb01ab20749d7b9254c3a4825e31
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 6cf3317fddf61454181264b523a2804e
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f9253ec9aa37d4fd28af570d9427c00b
timeCreated: 1702629767

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9ce9c7008577c4c04b10eb96a3244867
timeCreated: 1703409620

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3e096221d72bd44baa543f1629092c4a
timeCreated: 1703412483

View File

@ -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 "";
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d05ef4ba47b6e4cb7bf95cb073af4915
timeCreated: 1703413245

View File

@ -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();
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4012c7bdb57bc4bfbb3b313a86ea3901
timeCreated: 1702627784

View File

@ -0,0 +1,16 @@
using Guru.Editor;
using UnityEditor;
namespace Guru
{
public class GuruSDKMenuItems
{
[MenuItem("Guru/Guru SDK")]
private static void ShowGuruManager()
{
GuruSDKManager.Open();
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 7e6a90bd7ba03491d87943c2c1fcf17e
timeCreated: 1702861089

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 627835e82d65043cf8996da4a8377fa7
timeCreated: 1703231041

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a6aed96e95b747cdbb3c19c8d01b5f1
timeCreated: 1702786341

View File

@ -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
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 65cafb0a78f2a474eb82c73f624745d8
timeCreated: 1702611049

3
Runtime.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c0ee5782432f84c0a8d70e660102aabe
timeCreated: 1702610991

3
Runtime/Code.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8e84534c908cf44e3bb7d315216557da
timeCreated: 1702611028

3
Runtime/Code/Config.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e8c2747c350c2451089422bf119c2094
timeCreated: 1703505490

3
Runtime/Code/Core.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 99b9bdd32c352412598d6d22bf5438b6
timeCreated: 1702628339

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d1320ee3985cd4265906c63a00fd12d4
timeCreated: 1702628352

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b2b75eb78fc3c4f148365eb7e3d89bd7
timeCreated: 1703308617

View File

@ -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;
}
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 971089341f7a64ee38f8d3f82e40f59c
timeCreated: 1703307770

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2613bac8a776048ac9fd924c6dc7244f
timeCreated: 1703320826

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 62635518506334610aeaf54c9c29fe75
timeCreated: 1703035168

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e6c57dd4792204f5f9b778eb7e7cb920
timeCreated: 1703039335

View File

@ -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;
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5c9728047bb1049639340975b4e8d7ee
timeCreated: 1702861449

3
Runtime/Code/IAP.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2b0ce7d06a8234e3f9a0eb466c38f041
timeCreated: 1702627775

View File

@ -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++; // 记录成功购买次数
}
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f22899a5bf889441fba95e634696a74b
timeCreated: 1703320926

3
Runtime/Code/Model.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2093caa07830a41d5958de2faf589f13
timeCreated: 1703321414

View File

@ -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;
}
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc7bbb7d0d6ed42d7985198f9cfc3cb0
timeCreated: 1703323782

View File

@ -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
}
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9d518492c434042c6aeb20ce679df8ab
timeCreated: 1703321428

19
Runtime/GuruSDK.asmdef Normal file
View File

@ -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
}

View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 85fac0454e8c64a0da25f1f632acaa75
timeCreated: 1702611014

3
Runtime/Prefab.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: fc679813f31644f20b79c6f24939c6a9
timeCreated: 1702611035

5
link.xml Normal file
View File

@ -0,0 +1,5 @@
<linker>
<assembly fullname="GuruSDK">
<namespace fullname="Guru" preserve="all"/>
</assembly>
</linker>

3
link.xml.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 33d446758bba24852bac2e3d9c6bf6fc
timeCreated: 1703388178

15
package.json Normal file
View File

@ -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"
}
}

3
package.json.meta Normal file
View File

@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 2e68608e12de34fa69d2e96e7dcb8892
timeCreated: 1702610734