diff --git a/Assets/Editor/BFBuildProjectTools/BuildProjectWindow/BuildProjectWindow.cs b/Assets/Editor/BFBuildProjectTools/BuildProjectWindow/BuildProjectWindow.cs index 8fa567654..fd09eded9 100644 --- a/Assets/Editor/BFBuildProjectTools/BuildProjectWindow/BuildProjectWindow.cs +++ b/Assets/Editor/BFBuildProjectTools/BuildProjectWindow/BuildProjectWindow.cs @@ -18,7 +18,7 @@ namespace BFEditor.Build private static int VersionCodeRU = 12; private static string VersionNameRU = "0.4.9"; BFPlatformOptions platform = BFPlatformOptions.AndroidDev; - const string ANDROID_GP_PACKAGE_NAME = "com.c1.dev.android"; + const string ANDROID_GP_PACKAGE_NAME = "com.fortune.td.game.global"; public BuildProjectWindow() { diff --git a/Assets/Scripts/Const/BFPlatform.Language.cs b/Assets/Scripts/Const/BFPlatform.Language.cs index abc1d8bc2..e2fbba33f 100644 --- a/Assets/Scripts/Const/BFPlatform.Language.cs +++ b/Assets/Scripts/Const/BFPlatform.Language.cs @@ -42,7 +42,7 @@ namespace BF // 渠道对应的语言配置 public static Dictionary languageInfos = new Dictionary() { - {"com.c1.dev.android", new BFLanguageInfo(new List{"en", "cn", "zh", "th", "ru", "id", "vi"})}, + {"com.fortune.td.game.global", new BFLanguageInfo(new List{"en", "cn", "zh", "th", "ru", "id", "vi"})}, {"com.juzu.b6.dev.android", new BFLanguageInfo(new List{"en", "cn", "zh", "th", "ru", "id", "vi"})}, {"com.juzu.b6.dev.ios", new BFLanguageInfo(new List{"en", "cn"})}, {"com.juzu.b6.release.android", new BFLanguageInfo(new List{"en"})}, diff --git a/BFVersions/android/dz_dev/build.gradle b/BFVersions/android/dz_dev/build.gradle old mode 100644 new mode 100755 index 455b2415e..2e1ead0e0 --- a/BFVersions/android/dz_dev/build.gradle +++ b/BFVersions/android/dz_dev/build.gradle @@ -1,40 +1,40 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -buildscript { - repositories { - google() - jcenter() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' - // classpath 'com.google.gms:google-services:4.3.13' - // classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' - } -} - -allprojects { - buildscript { - repositories { - google() - jcenter() - } - -// dependencies { -// classpath 'com.android.tools.build:gradle:4.0.1' -// -// } - } - - repositories { - google() - jcenter() - flatDir { - dirs "${project(':unityLibrary').projectDir}/libs" - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +buildscript { + repositories { + google() + jcenter() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.google.gms:google-services:4.3.13' + // classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' + } +} + +allprojects { + buildscript { + repositories { + google() + jcenter() + } + +// dependencies { +// classpath 'com.android.tools.build:gradle:4.0.1' +// +// } + } + + repositories { + google() + jcenter() + flatDir { + dirs "${project(':unityLibrary').projectDir}/libs" + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/BFVersions/android/dz_dev/gradle.properties b/BFVersions/android/dz_dev/gradle.properties old mode 100644 new mode 100755 index 58e8481f1..0521300d1 --- a/BFVersions/android/dz_dev/gradle.properties +++ b/BFVersions/android/dz_dev/gradle.properties @@ -1,6 +1,6 @@ -org.gradle.jvmargs=-Xmx4096M -org.gradle.parallel=true -android.enableR8=false -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx4096M +org.gradle.parallel=true +android.enableR8=false +android.useAndroidX=true +android.enableJetifier=true unityStreamingAssets=.unity3d, .bytes, .ab \ No newline at end of file diff --git a/BFVersions/android/dz_dev/unityLibrary/build.gradle b/BFVersions/android/dz_dev/unityLibrary/build.gradle old mode 100644 new mode 100755 index 89045132b..e61b2d3a5 --- a/BFVersions/android/dz_dev/unityLibrary/build.gradle +++ b/BFVersions/android/dz_dev/unityLibrary/build.gradle @@ -1,119 +1,97 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.library' - -// Android Resolver Repos Start -([rootProject] + (rootProject.subprojects as List)).each { project -> - project.repositories { - def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/") - maven { - url "https://maven.google.com" - } - maven { - url "https://android-sdk.is.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:9, Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:16, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:16, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8, Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:8, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:16, Assets/IronSource/Editor/ISLiftoffAdapterDependencies.xml:16, Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:8, Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:8, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8 - } - maven { - url "https://maven.google.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:17, Assets/IronSource/Editor/IronSourceSDKDependencies.xml:25, Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:8, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:8, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15, Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:15, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:8, Assets/IronSource/Editor/ISLiftoffAdapterDependencies.xml:8, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 - } - maven { - url "https://artifact.bytedance.com/repository/pangle/" // Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:15 - } - maven { - url "https://sdk.tapjoy.com/" // Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:15 - } - mavenLocal() - jcenter() - mavenCentral() - } -} -// Android Resolver Repos End - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:multidex:1.0.3' - - implementation(name: 'screenutils-release', ext:'aar') - implementation(name: 'ThinkingSDK', ext:'aar') - implementation(name: 'UnityUtils-release', ext:'aar') - implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') - implementation 'com.google.android.gms:play-services-auth:20.1.0' - implementation "com.android.billingclient:billing:5.0.0" - - // firebase - // implementation 'com.google.firebase:firebase-analytics:21.1.0' - // implementation 'com.google.firebase:firebase-crashlytics:18.2.12' - // implementation 'com.google.firebase:firebase-messaging:23.0.8' - - // Android Resolver Dependencies Start - implementation 'com.adcolony:sdk:4.8.0' // Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:8 - implementation 'com.android.installreferrer:installreferrer:2.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:10 - implementation 'com.android.support:appcompat-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:cardview-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:customtabs:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:support-v4:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.applovin:applovin-sdk:11.7.1' // Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15 - implementation 'com.appsflyer:af-android-sdk:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:6 - implementation 'com.appsflyer:unity-wrapper:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:8 - implementation 'com.chartboost:chartboost-sdk:9.2.0' // Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:15 - implementation 'com.facebook.android:audience-network-sdk:6.12.0' // Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:8 - implementation 'com.facebook.android:facebook-applinks:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:6 - implementation 'com.facebook.android:facebook-core:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:5 - implementation 'com.facebook.android:facebook-gamingservices:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:9 - implementation 'com.facebook.android:facebook-login:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:7 - implementation 'com.facebook.android:facebook-share:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:8 - implementation 'com.google.android.gms:play-services-ads:21.5.0' // Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:8 - implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:17 - implementation 'com.google.android.gms:play-services-basement:18.1.0' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:25 - implementation 'com.ironsource.adapters:adcolonyadapter:4.3.14' // Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:admobadapter:4.3.35' // Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:applovinadapter:4.3.37' // Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:chartboostadapter:4.3.11' // Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:facebookadapter:4.3.39' // Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:liftoffadapter:4.3.5' // Assets/IronSource/Editor/ISLiftoffAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:pangleadapter:4.3.17' // Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:tapjoyadapter:4.1.24' // Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:unityadsadapter:4.3.26' // Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8 - implementation 'com.ironsource.sdk:mediationsdk:7.3.0' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:9 - implementation 'com.pangle.global:ads-sdk:5.0.0.8' // Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:15 - implementation 'com.parse.bolts:bolts-android:1.4.0' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:4 - implementation 'com.tapjoy:tapjoy-android-sdk:12.11.1' // Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:15 - implementation 'com.unity3d.ads:unity-ads:4.6.0' // Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 - implementation 'io.liftoff:liftoffads:1.9.1' // Assets/IronSource/Editor/ISLiftoffAdapterDependencies.xml:8 -// Android Resolver Dependencies End -} - -android { - compileSdkVersion 30 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 - ndk { - abiFilters 'armeabi-v7a' - } - versionCode 1 - versionName '0.1.0' - consumerProguardFiles 'proguard-unity.txt' - } - - lintOptions { - abortOnError false - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - } -} - - +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.library' + +// Android Resolver Repos Start +([rootProject] + (rootProject.subprojects as List)).each { project -> + project.repositories { + def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/") + maven { + url "https://maven.google.com" + } + maven { + url "https://android-sdk.is.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:9, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:16, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:16, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8 + } + maven { + url "https://maven.google.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:17, Assets/IronSource/Editor/IronSourceSDKDependencies.xml:25, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:8, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:8, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 + } + mavenLocal() + jcenter() + mavenCentral() + } +} +// Android Resolver Repos End + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:multidex:1.0.3' + + implementation(name: 'screenutils-release', ext:'aar') + implementation(name: 'ThinkingSDK', ext:'aar') + implementation(name: 'UnityUtils-release', ext:'aar') + implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') + implementation 'com.google.android.gms:play-services-auth:20.1.0' + implementation "com.android.billingclient:billing:5.0.0" +// Android Resolver Dependencies Start + implementation 'com.android.installreferrer:installreferrer:2.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:10 + implementation 'com.android.support:appcompat-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.android.support:cardview-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.android.support:customtabs:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.android.support:support-v4:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.applovin:applovin-sdk:11.5.5' // Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15 + implementation 'com.appsflyer:af-android-sdk:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:6 + implementation 'com.appsflyer:unity-wrapper:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:8 + implementation 'com.facebook.android:audience-network-sdk:6.12.0' // Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:8 + implementation 'com.facebook.android:facebook-applinks:[11.0, 12)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:6 + implementation 'com.facebook.android:facebook-core:[11.0, 12)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:5 + implementation 'com.facebook.android:facebook-gamingservices:[11.0, 12)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:9 + implementation 'com.facebook.android:facebook-login:[11.0, 12)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:7 + implementation 'com.facebook.android:facebook-share:[11.0, 12)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:8 + implementation 'com.google.android.gms:play-services-ads:21.3.0' // Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:8 + implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:17 + implementation 'com.google.android.gms:play-services-basement:18.1.0' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:25 + implementation 'com.ironsource.adapters:admobadapter:4.3.33' // Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:16 + implementation 'com.ironsource.adapters:applovinadapter:4.3.35' // Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8 + implementation 'com.ironsource.adapters:facebookadapter:4.3.38' // Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:16 + implementation 'com.ironsource.adapters:unityadsadapter:4.3.24' // Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8 + implementation 'com.ironsource.sdk:mediationsdk:7.2.6' // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:9 + implementation 'com.parse.bolts:bolts-android:1.4.0' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:4 + implementation 'com.unity3d.ads:unity-ads:4.4.1' // Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 +// Android Resolver Dependencies End +} + +android { + compileSdkVersion 30 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 30 + ndk { + abiFilters 'armeabi-v7a' + } + versionCode 1 + versionName '0.1.0' + consumerProguardFiles 'proguard-unity.txt' + } + + lintOptions { + abortOnError false + } + + aaptOptions { + noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + } +} + + diff --git a/BFVersions/android/dz_dev/unityLibrary/src/main/AndroidManifest.xml b/BFVersions/android/dz_dev/unityLibrary/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 95adb4109..6bee77a4b --- a/BFVersions/android/dz_dev/unityLibrary/src/main/AndroidManifest.xml +++ b/BFVersions/android/dz_dev/unityLibrary/src/main/AndroidManifest.xml @@ -1,66 +1,65 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REPLACE_BUILD_ID - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + REPLACE_BUILD_ID + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BFVersions/android/dz_dev/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java b/BFVersions/android/dz_dev/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java old mode 100644 new mode 100755 index ca3396058..734058448 --- a/BFVersions/android/dz_dev/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java +++ b/BFVersions/android/dz_dev/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java @@ -1,188 +1,177 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN -package com.unity3d.player; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.PixelFormat; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.os.Process; -// import android.os.Build; - -// import com.chartboost.sdk.Chartboost; -import com.juzu.dz.third.GooglePlugin; -import com.ironsource.mediationsdk.IronSource; - -public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents -{ - protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code - - // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player - // The command line arguments are passed as a string, separated by spaces - // UnityPlayerActivity calls this from 'onCreate' - // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan - // See https://docs.unity3d.com/Manual/CommandLineArguments.html - // @param cmdLine the current command line arguments, may be null - // @return the modified command line string or null - protected String updateUnityCommandLineArguments(String cmdLine) - { - return cmdLine; - } - - // Setup activity layout - @Override protected void onCreate(Bundle savedInstanceState) - { - requestWindowFeature(Window.FEATURE_NO_TITLE); - super.onCreate(savedInstanceState); - - String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); - getIntent().putExtra("unity", cmdLine); - - mUnityPlayer = new UnityPlayer(this, this); - setContentView(mUnityPlayer); - mUnityPlayer.requestFocus(); - - GooglePlugin.init(this); - } - - // When Unity player unloaded move task to background - @Override public void onUnityPlayerUnloaded() { - moveTaskToBack(true); - } - - // Callback before Unity player process is killed - @Override public void onUnityPlayerQuitted() { - } - - @Override protected void onNewIntent(Intent intent) - { - // To support deep linking, we need to make sure that the client can get access to - // the last sent intent. The clients access this through a JNI api that allows them - // to get the intent set on launch. To update that after launch we have to manually - // replace the intent with the one caught here. - setIntent(intent); - mUnityPlayer.newIntent(intent); - } - - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - GooglePlugin.onActivityResult(requestCode, resultCode, data); - } - - // Quit Unity - @Override protected void onDestroy () - { - GooglePlugin.onDestroy(); - mUnityPlayer.destroy(); - super.onDestroy(); - } - - // If the activity is in multi window mode or resizing the activity is allowed we will use - // onStart/onStop (the visibility callbacks) to determine when to pause/resume. - // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve - // existing behavior. - @Override protected void onStop() - { - super.onStop(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - } - - @Override protected void onStart() - { - super.onStart(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - } - - // Pause Unity - @Override protected void onPause() - { - super.onPause(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - IronSource.onPause(this); - } - - // Resume Unity - @Override protected void onResume() - { - super.onResume(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - IronSource.onResume(this); - } - - @Override - public void onBackPressed() { - // If an interstitial is on screen, close it. - // if (Chartboost.onBackPressed()) { - // return; - // } else { - // super.onBackPressed(); - // } - } - - // Low Memory Unity - @Override public void onLowMemory() - { - super.onLowMemory(); - mUnityPlayer.lowMemory(); - } - - // Trim Memory Unity - @Override public void onTrimMemory(int level) - { - super.onTrimMemory(level); - if (level == TRIM_MEMORY_RUNNING_CRITICAL) - { - mUnityPlayer.lowMemory(); - } - } - - // This ensures the layout will be correct. - @Override public void onConfigurationChanged(Configuration newConfig) - { - super.onConfigurationChanged(newConfig); - mUnityPlayer.configurationChanged(newConfig); - } - - // Notify Unity of the focus change. - @Override public void onWindowFocusChanged(boolean hasFocus) - { - super.onWindowFocusChanged(hasFocus); - mUnityPlayer.windowFocusChanged(hasFocus); - } - - // For some reason the multiple keyevent type is not supported by the ndk. - // Force event injection by overriding dispatchKeyEvent(). - @Override public boolean dispatchKeyEvent(KeyEvent event) - { - if (event.getAction() == KeyEvent.ACTION_MULTIPLE) - return mUnityPlayer.injectEvent(event); - return super.dispatchKeyEvent(event); - } - - // Pass any events not handled by (unfocused) views straight to UnityPlayer - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } - /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN +package com.unity3d.player; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.os.Process; + +// import com.chartboost.sdk.Chartboost; +import com.juzu.dz.third.GooglePlugin; +// import com.ironsource.mediationsdk.IronSource; + +public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents +{ + protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code + + // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player + // The command line arguments are passed as a string, separated by spaces + // UnityPlayerActivity calls this from 'onCreate' + // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan + // See https://docs.unity3d.com/Manual/CommandLineArguments.html + // @param cmdLine the current command line arguments, may be null + // @return the modified command line string or null + protected String updateUnityCommandLineArguments(String cmdLine) + { + return cmdLine; + } + + // Setup activity layout + @Override protected void onCreate(Bundle savedInstanceState) + { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState); + + String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); + getIntent().putExtra("unity", cmdLine); + + mUnityPlayer = new UnityPlayer(this, this); + setContentView(mUnityPlayer); + mUnityPlayer.requestFocus(); + + GooglePlugin.init(this); + } + + // When Unity player unloaded move task to background + @Override public void onUnityPlayerUnloaded() { + moveTaskToBack(true); + } + + // Callback before Unity player process is killed + @Override public void onUnityPlayerQuitted() { + } + + @Override protected void onNewIntent(Intent intent) + { + // To support deep linking, we need to make sure that the client can get access to + // the last sent intent. The clients access this through a JNI api that allows them + // to get the intent set on launch. To update that after launch we have to manually + // replace the intent with the one caught here. + setIntent(intent); + mUnityPlayer.newIntent(intent); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + GooglePlugin.onActivityResult(requestCode, resultCode, data); + } + + // Quit Unity + @Override protected void onDestroy () + { + GooglePlugin.onDestroy(); + mUnityPlayer.destroy(); + super.onDestroy(); + } + + // If the activity is in multi window mode or resizing the activity is allowed we will use + // onStart/onStop (the visibility callbacks) to determine when to pause/resume. + // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve + // existing behavior. + @Override protected void onStop() + { + super.onStop(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + } + + @Override protected void onStart() + { + super.onStart(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + } + + // Pause Unity + @Override protected void onPause() + { + super.onPause(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + // IronSource.onPause(this); + } + + // Resume Unity + @Override protected void onResume() + { + super.onResume(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + // IronSource.onResume(this); + } + + // Low Memory Unity + @Override public void onLowMemory() + { + super.onLowMemory(); + mUnityPlayer.lowMemory(); + } + + // Trim Memory Unity + @Override public void onTrimMemory(int level) + { + super.onTrimMemory(level); + if (level == TRIM_MEMORY_RUNNING_CRITICAL) + { + mUnityPlayer.lowMemory(); + } + } + + // This ensures the layout will be correct. + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + mUnityPlayer.configurationChanged(newConfig); + } + + // Notify Unity of the focus change. + @Override public void onWindowFocusChanged(boolean hasFocus) + { + super.onWindowFocusChanged(hasFocus); + mUnityPlayer.windowFocusChanged(hasFocus); + } + + // For some reason the multiple keyevent type is not supported by the ndk. + // Force event injection by overriding dispatchKeyEvent(). + @Override public boolean dispatchKeyEvent(KeyEvent event) + { + if (event.getAction() == KeyEvent.ACTION_MULTIPLE) + return mUnityPlayer.injectEvent(event); + return super.dispatchKeyEvent(event); + } + + // Pass any events not handled by (unfocused) views straight to UnityPlayer + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } + /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } +} diff --git a/BFVersions/android/dz_dev/unityLibrary/src/main/res/xml/network_security_config.xml b/BFVersions/android/dz_dev/unityLibrary/src/main/res/xml/network_security_config.xml old mode 100644 new mode 100755 index 3f9b9c92f..0edfdf604 --- a/BFVersions/android/dz_dev/unityLibrary/src/main/res/xml/network_security_config.xml +++ b/BFVersions/android/dz_dev/unityLibrary/src/main/res/xml/network_security_config.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/BFVersions/android/dz_google_abb/build.gradle b/BFVersions/android/dz_google_abb/build.gradle old mode 100644 new mode 100755 index 245f232d9..99cfaa109 --- a/BFVersions/android/dz_google_abb/build.gradle +++ b/BFVersions/android/dz_google_abb/build.gradle @@ -1,37 +1,37 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -buildscript { - repositories { - google() - jcenter() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' - } -} - -allprojects { - buildscript { - repositories { - google() - jcenter() - } - -// dependencies { -// classpath 'com.android.tools.build:gradle:4.0.1' -// -// } - } - - repositories { - google() - jcenter() - flatDir { - dirs "${project(':unityLibrary').projectDir}/libs" - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.1' + } +} + +allprojects { + buildscript { + repositories { + google() + jcenter() + } + +// dependencies { +// classpath 'com.android.tools.build:gradle:4.0.1' +// +// } + } + + repositories { + google() + jcenter() + flatDir { + dirs "${project(':unityLibrary').projectDir}/libs" + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/BFVersions/android/dz_google_abb/gradle.properties b/BFVersions/android/dz_google_abb/gradle.properties old mode 100644 new mode 100755 index 58e8481f1..0521300d1 --- a/BFVersions/android/dz_google_abb/gradle.properties +++ b/BFVersions/android/dz_google_abb/gradle.properties @@ -1,6 +1,6 @@ -org.gradle.jvmargs=-Xmx4096M -org.gradle.parallel=true -android.enableR8=false -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx4096M +org.gradle.parallel=true +android.enableR8=false +android.useAndroidX=true +android.enableJetifier=true unityStreamingAssets=.unity3d, .bytes, .ab \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/install_time_pack/build.gradle b/BFVersions/android/dz_google_abb/install_time_pack/build.gradle old mode 100644 new mode 100755 index 1c9945271..50e09a19c --- a/BFVersions/android/dz_google_abb/install_time_pack/build.gradle +++ b/BFVersions/android/dz_google_abb/install_time_pack/build.gradle @@ -1,7 +1,7 @@ -apply plugin: 'com.android.asset-pack' -assetPack{ - packName = "install_time_pack" - dynamicDelivery { - deliveryType = "install-time" - } +apply plugin: 'com.android.asset-pack' +assetPack{ + packName = "install_time_pack" + dynamicDelivery { + deliveryType = "install-time" + } } \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/launcher/build.gradle b/BFVersions/android/dz_google_abb/launcher/build.gradle old mode 100644 new mode 100755 index 3bf656b34..b282ea96e --- a/BFVersions/android/dz_google_abb/launcher/build.gradle +++ b/BFVersions/android/dz_google_abb/launcher/build.gradle @@ -1,74 +1,74 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.application' - -dependencies { - implementation platform('com.google.firebase:firebase-bom:29.2.1') - implementation project(':unityLibrary') - implementation 'com.google.android.play:core:1.10.0' - } - -android { - assetPacks = [":install_time_pack"] - - compileSdkVersion 30 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 - applicationId 'com.idlelegend.arenaclash.battlefire' - ndk { - abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' - } - versionCode 1 - versionName '0.1.0' - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - lintOptions { - abortOnError false - } - - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - signingConfig signingConfigs.debug - jniDebuggable true - } - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - signingConfig signingConfigs.debug - } - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - doNotStrip '*/arm64-v8a/*.so' - doNotStrip '*/x86/*.so' - doNotStrip '*/x86_64/*.so' - } - - bundle { - language { - enableSplit = false - } - density { - enableSplit = false - } - abi { - enableSplit = true - } - } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.application' + +dependencies { + implementation platform('com.google.firebase:firebase-bom:29.2.1') + implementation project(':unityLibrary') + implementation 'com.google.android.play:core:1.10.0' + } + +android { + assetPacks = [":install_time_pack"] + + compileSdkVersion 30 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 30 + applicationId 'com.idlelegend.arenaclash.battlefire' + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + } + versionCode 1 + versionName '0.1.0' + } + + aaptOptions { + noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + lintOptions { + abortOnError false + } + + buildTypes { + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt') + signingConfig signingConfigs.debug + jniDebuggable true + } + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt') + signingConfig signingConfigs.debug + } + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + doNotStrip '*/arm64-v8a/*.so' + doNotStrip '*/x86/*.so' + doNotStrip '*/x86_64/*.so' + } + + bundle { + language { + enableSplit = false + } + density { + enableSplit = false + } + abi { + enableSplit = true + } + } +} diff --git a/BFVersions/android/dz_google_abb/launcher/src/main/AndroidManifest.xml b/BFVersions/android/dz_google_abb/launcher/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 3239553be..579b7548c --- a/BFVersions/android/dz_google_abb/launcher/src/main/AndroidManifest.xml +++ b/BFVersions/android/dz_google_abb/launcher/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/launcher/src/main/res/drawable/firebase_icon.png b/BFVersions/android/dz_google_abb/launcher/src/main/res/drawable/firebase_icon.png old mode 100644 new mode 100755 diff --git a/BFVersions/android/dz_google_abb/unityLibrary/build.gradle b/BFVersions/android/dz_google_abb/unityLibrary/build.gradle old mode 100644 new mode 100755 index 83a20ea5e..06a480bee --- a/BFVersions/android/dz_google_abb/unityLibrary/build.gradle +++ b/BFVersions/android/dz_google_abb/unityLibrary/build.gradle @@ -1,125 +1,125 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.library' - - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation(name: 'androidx.activity.activity-1.0.0', ext:'aar') - implementation(name: 'androidx.appcompat.appcompat-1.1.0', ext:'aar') - implementation(name: 'androidx.appcompat.appcompat-resources-1.1.0', ext:'aar') - implementation(name: 'androidx.browser.browser-1.0.0', ext:'aar') - implementation(name: 'androidx.cardview.cardview-1.0.0', ext:'aar') - implementation(name: 'androidx.core.core-ktx-1.3.2', ext:'aar') - implementation(name: 'androidx.legacy.legacy-support-v4-1.0.0', ext:'aar') - implementation(name: 'androidx.media.media-1.0.0', ext:'aar') - implementation(name: 'androidx.savedstate.savedstate-1.0.0', ext:'aar') - implementation(name: 'androidx.vectordrawable.vectordrawable-animated-1.1.0', ext:'aar') - implementation(name: 'com.android.installreferrer.installreferrer-2.1', ext:'aar') - implementation(name: 'com.appsflyer.af-android-sdk-6.4.1', ext:'aar') - implementation(name: 'com.appsflyer.oaid-6.2.4', ext:'aar') - implementation(name: 'com.appsflyer.unity-wrapper-6.4.1', ext:'aar') - implementation(name: 'com.facebook.android.facebook-applinks-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-common-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-core-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-gamingservices-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-login-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-share-11.3.0', ext:'aar') - implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') - implementation(name: 'screenutils-release', ext:'aar') - implementation(name: 'ThinkingSDK', ext:'aar') - implementation(name: 'UnityUtils-release', ext:'aar') - implementation 'com.google.android.gms:play-services-auth:20.1.0' - implementation "com.android.billingclient:billing:5.0.0" - implementation platform('com.google.firebase:firebase-bom:29.2.1') - implementation 'com.google.firebase:firebase-analytics:21.1.0' - implementation 'com.google.firebase:firebase-messaging' -} - -android { - compileSdkVersion 30 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 - ndk { - abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' - } - versionCode 1 - versionName '0.1.0' - consumerProguardFiles 'proguard-unity.txt' - } - - lintOptions { - abortOnError false - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - doNotStrip '*/arm64-v8a/*.so' - doNotStrip '*/x86/*.so' - doNotStrip '*/x86_64/*.so' - } -} - -def getSdkDir() { - Properties local = new Properties() - local.load(new FileInputStream("${rootDir}/local.properties")) - return local.getProperty('sdk.dir') -} - -def BuildIl2Cpp(String workingDir, String targetDirectory, String architecture, String abi, String configuration) { - exec { - commandLine(workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/netcoreapp3.1/il2cpp", - "--compile-cpp", - "--libil2cpp-static", - "--platform=Android", - "--architecture=" + architecture, - "--configuration=" + configuration, - "--outputpath=" + workingDir + targetDirectory + abi + "/libil2cpp.so", - "--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/external/bdwgc/include", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/include", - "--tool-chain-path=" + android.ndkDirectory, - "--map-file-parser=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/MapFileParser/MapFileParser.exe", - "--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput", - "--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi, - "--dotnetprofile=unityaot") - environment "ANDROID_SDK_ROOT", getSdkDir() - } - delete workingDir + targetDirectory + abi + "/libil2cpp.sym.so" - ant.move(file: workingDir + targetDirectory + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") -} - -android { - task BuildIl2CppTask { - doLast { - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARMv7', 'armeabi-v7a', 'Release'); - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARM64', 'arm64-v8a', 'Release'); - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'x86', 'x86', 'Release'); - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'x64', 'x86_64', 'Release'); - } - } - afterEvaluate { - if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) - project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask - if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) - project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask - } - sourceSets { - main { - jni.srcDirs = ["src/main/Il2CppOutputProject"] - } - } +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.library' + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation(name: 'androidx.activity.activity-1.0.0', ext:'aar') + implementation(name: 'androidx.appcompat.appcompat-1.1.0', ext:'aar') + implementation(name: 'androidx.appcompat.appcompat-resources-1.1.0', ext:'aar') + implementation(name: 'androidx.browser.browser-1.0.0', ext:'aar') + implementation(name: 'androidx.cardview.cardview-1.0.0', ext:'aar') + implementation(name: 'androidx.core.core-ktx-1.3.2', ext:'aar') + implementation(name: 'androidx.legacy.legacy-support-v4-1.0.0', ext:'aar') + implementation(name: 'androidx.media.media-1.0.0', ext:'aar') + implementation(name: 'androidx.savedstate.savedstate-1.0.0', ext:'aar') + implementation(name: 'androidx.vectordrawable.vectordrawable-animated-1.1.0', ext:'aar') + implementation(name: 'com.android.installreferrer.installreferrer-2.1', ext:'aar') + implementation(name: 'com.appsflyer.af-android-sdk-6.4.1', ext:'aar') + implementation(name: 'com.appsflyer.oaid-6.2.4', ext:'aar') + implementation(name: 'com.appsflyer.unity-wrapper-6.4.1', ext:'aar') + implementation(name: 'com.facebook.android.facebook-applinks-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-common-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-core-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-gamingservices-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-login-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-share-11.3.0', ext:'aar') + implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') + implementation(name: 'screenutils-release', ext:'aar') + implementation(name: 'ThinkingSDK', ext:'aar') + implementation(name: 'UnityUtils-release', ext:'aar') + implementation 'com.google.android.gms:play-services-auth:20.1.0' + implementation "com.android.billingclient:billing:4.0.0" + implementation platform('com.google.firebase:firebase-bom:29.2.1') + implementation 'com.google.firebase:firebase-analytics:21.1.0' + implementation 'com.google.firebase:firebase-messaging' +} + +android { + compileSdkVersion 30 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 30 + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64' + } + versionCode 1 + versionName '0.1.0' + consumerProguardFiles 'proguard-unity.txt' + } + + lintOptions { + abortOnError false + } + + aaptOptions { + noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + doNotStrip '*/arm64-v8a/*.so' + doNotStrip '*/x86/*.so' + doNotStrip '*/x86_64/*.so' + } +} + +def getSdkDir() { + Properties local = new Properties() + local.load(new FileInputStream("${rootDir}/local.properties")) + return local.getProperty('sdk.dir') +} + +def BuildIl2Cpp(String workingDir, String targetDirectory, String architecture, String abi, String configuration) { + exec { + commandLine(workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/netcoreapp3.1/il2cpp", + "--compile-cpp", + "--libil2cpp-static", + "--platform=Android", + "--architecture=" + architecture, + "--configuration=" + configuration, + "--outputpath=" + workingDir + targetDirectory + abi + "/libil2cpp.so", + "--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache", + "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/external/bdwgc/include", + "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/include", + "--tool-chain-path=" + android.ndkDirectory, + "--map-file-parser=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/MapFileParser/MapFileParser.exe", + "--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput", + "--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi, + "--dotnetprofile=unityaot") + environment "ANDROID_SDK_ROOT", getSdkDir() + } + delete workingDir + targetDirectory + abi + "/libil2cpp.sym.so" + ant.move(file: workingDir + targetDirectory + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") +} + +android { + task BuildIl2CppTask { + doLast { + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARMv7', 'armeabi-v7a', 'Release'); + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARM64', 'arm64-v8a', 'Release'); + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'x86', 'x86', 'Release'); + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'x64', 'x86_64', 'Release'); + } + } + afterEvaluate { + if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) + project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask + if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) + project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask + } + sourceSets { + main { + jni.srcDirs = ["src/main/Il2CppOutputProject"] + } + } } \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/AndroidManifest.xml b/BFVersions/android/dz_google_abb/unityLibrary/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 93e2fcce3..fbc021c38 --- a/BFVersions/android/dz_google_abb/unityLibrary/src/main/AndroidManifest.xml +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/AndroidManifest.xml @@ -1,67 +1,66 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REPLACE_BUILD_ID - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + REPLACE_BUILD_ID + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java new file mode 100755 index 000000000..d4783688f --- /dev/null +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java @@ -0,0 +1,30 @@ +package com.juzu.dz.message; + +/** + * 管理和前端的通信消息以及json字段 + * */ +public class BFMessage { + // Google登录 + public static final int GOOGLE_LOGIN_SUCCESS = 1; + public static final int GOOGLE_LOGIN_FAILED = 2; + // Google登出成功 + public static final int GOOGLE_LOGOUT_SUCCESS = 3; + // Google支付 + public static final int GOOGLE_PAY_SUCCESS = 4; + public static final int GOOGLE_PAY_FAILED = 5; + public static final int GOOGLE_PAY_CANCEL = 6; + public static final int GOOGLE_CONNECT_SUCCESS = 7; + public static final int GOOGLE_CONNECT_FAILED = 8; + public static final int QUERY_PRODUCT_SUCCESS = 9; + public static final int QUERY_PRODUCT_FAILED = 10; + public static final int QUERY_UNCOMPLETE_ORDER_FINISH = 11; + // Google消耗 + public static final int GOOGLE_CONSUME_SUCCESS = 12; + public static final int GOOGLE_CONSUME_FAILED = 13; + // Google登出失败 + public static final int GOOGLE_LOGOUT_FAILED = 14; + // fireBaseToken + public static final int FIREBASE_TOKEN = 15; + // Google订阅 + public static final int QUERY_SUBSCRIBE_FINISH = 16; +} diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java new file mode 100755 index 000000000..ba6174633 --- /dev/null +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java @@ -0,0 +1,459 @@ +package com.juzu.dz.third; + +import android.app.Activity; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.billingclient.api.AccountIdentifiers; +import com.android.billingclient.api.AcknowledgePurchaseParams; +import com.android.billingclient.api.AcknowledgePurchaseResponseListener; +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingResult; +import com.android.billingclient.api.ConsumeParams; +import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.PurchasesUpdatedListener; +import com.android.billingclient.api.SkuDetails; +import com.android.billingclient.api.SkuDetailsParams; +import com.android.billingclient.api.SkuDetailsResponseListener; +import com.juzu.dz.message.BFMessage; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GoogleBilling { + private static volatile GoogleBilling sInstance; + private static final String LOG_TAG = "GoogleBilling"; + private static BillingClient mGoogleBillingClient; + private Map mPurchase = new HashMap(); + private List mSubList = new ArrayList(); + private List mInAppList = new ArrayList(); + final private static String BASE_64_ENCODED_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm2Vcz26Jz82oYAkr8Wsk0z0hgwBLDRbmnQyARqusiSaJWOt9vEaTgLtLaWYYIiWIeWXUaKq35xDHjC5Xh+KI/pp5N7ck1yB5+lyaSsVD0ESFC/qjDWgElaxxL9QvOyLEHd23q9TmlF1aWziSc6ryFX9HVEGLJT2bTjVEz/bk/WpfN41HZafqQTCIWh8+vRgr0CXa/JEqysjDYRpbaBViPE9F7aTo8lCv/VQpE1ycFiOoaf768aispY5cXb0qP00li95HAI+fEaYgxOuRmN0oc5BFpNRNYTMmRX1Oi5F2vknw+u3+mh+a6GkbwD6FCK+fWIo8hZAWnkULgrxa1ReobQIDAQAB"; + + public static GoogleBilling getInstance() + { + if (sInstance == null) { + synchronized (GoogleBilling.class) { + if (sInstance == null) { + sInstance = new GoogleBilling(); + } + } + } + return sInstance; + } + + public void init(Activity activity){ + mGoogleBillingClient = BillingClient.newBuilder(activity).setListener(payListener).enablePendingPurchases().build(); + connectGoogleStore(); + } + + public void connectGoogleStore(){ + mGoogleBillingClient.startConnection(new BillingClientStateListener() { + @Override + public void onBillingSetupFinished(BillingResult billingResult) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_SUCCESS, ""); + }else{ + String msg = billingResult.getDebugMessage(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); + } + } + + @Override + public void onBillingServiceDisconnected() { + String msg = "disconnected"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); + } + }); + } + + // 查询商品信息,本地化用 + public void queryProductsInfo(String payType, String productInfoJson){ + Log.d(LOG_TAG, "google queryProductsInfo info from unity:" + productInfoJson); + try { + JSONArray array = new JSONArray(productInfoJson); + String[] proList = new String[array.length()]; + for (int i = 0; i < array.length(); i++){ + proList[i] = (String)array.get(i); + } + queryProducts(payType, proList); + } catch (JSONException e) { + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, e.toString()); + } + } + + //通过商品id查询商品详情 + private void queryProducts(String payType, String [] products){ + List pList = Arrays.asList(products); + SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); + params.setSkusList(pList).setType(payType); + mGoogleBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { + @Override + public void onSkuDetailsResponse(BillingResult billingResult, List list) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null){ + Log.d(LOG_TAG, "queryProducts success count:" + list.size()); + if (list.size() == 0){ + String msg = "未查询到商品信息,请检查传入的商品id,或者配置是否生效"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); + return; + } + JSONArray array = new JSONArray(); + List mList = new ArrayList(); + for (SkuDetails skuDetails : list) { + mList.add(skuDetails); + String sku = skuDetails.getSku(); + String price = skuDetails.getPrice();//实际价格 + String originPrice = skuDetails.getOriginalPrice();//原价,如果没折扣,原价=实际价格 + String description = skuDetails.getDescription(); + String originalJson = skuDetails.getOriginalJson(); + String title = skuDetails.getTitle(); + String priceAmountMicros = String.valueOf(skuDetails.getPriceAmountMicros()); + String currencyCode = skuDetails.getPriceCurrencyCode(); + JSONObject info = new JSONObject(); + try { + info.put("sku", sku); + info.put("price", price); + info.put("originPrice", originPrice); + info.put("description", description); + info.put("originalJson", originalJson); + info.put("title", title); + info.put("priceCurrencyCode", currencyCode); + info.put("priceAmountMicros", priceAmountMicros); + } catch (JSONException e) { + e.printStackTrace(); + } + array.put(info); + } + if(payType.equals(BillingClient.SkuType.INAPP)){ + mInAppList = mList; + } + if(payType.equals(BillingClient.SkuType.SUBS)){ + mSubList = mList; + } + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_SUCCESS, array.toString()); + }else{ + String msg = "queryProducts error:" + billingResult.getResponseCode(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); + } + } + }); + } + + // 支付 + public void pay(Activity activity, String payType, String productId, String customMsg){ + List skuList = null; + if(payType.equals(BillingClient.SkuType.INAPP)){ + skuList = mInAppList; + } + if(payType.equals(BillingClient.SkuType.SUBS)){ + skuList = mSubList; + } + if (skuList == null || skuList.size() == 0){ + String msg = "no sku"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + return ; + } + SkuDetails paySku = null; + for (SkuDetails details:skuList){ + if (TextUtils.equals(productId, details.getSku())){ + paySku = details; + break; + } + } + if (paySku == null){ + String msg = "sku not found! please contact developer"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + return; + } + // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSkuDetails(paySku) + .setObfuscatedAccountId(customMsg) + .build(); + BillingResult result = mGoogleBillingClient.launchBillingFlow(activity, flowParams); + if (result.getResponseCode() != BillingClient.BillingResponseCode.OK){ + String msg = "Billing failed: + " + result.getDebugMessage(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + } + + private PurchasesUpdatedListener payListener = new PurchasesUpdatedListener() { + @Override + public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List purchases) { + switch (billingResult.getResponseCode()) { + case BillingClient.BillingResponseCode.OK: + if (null != purchases) { + for (Purchase purchase : purchases) { + handlePurchase(purchase); + } + } else { + String msg = "Null Purchase List Returned from OK response!"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + break; + case BillingClient.BillingResponseCode.USER_CANCELED: + Log.i(LOG_TAG, "onPurchasesUpdated: User canceled the purchase"); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_CANCEL, ""); + break; + case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED: + String msg = "onPurchasesUpdated: The user already owns this item"; + Log.i(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + break; + case BillingClient.BillingResponseCode.DEVELOPER_ERROR: + String msg2 = "onPurchasesUpdated: Developer error means that Google Play " + + "does not recognize the configuration. If you are just getting started, " + + "make sure you have configured the application correctly in the " + + "Google Play Console. The SKU product ID must match and the APK you " + + "are using must be signed with release keys."; + + Log.e(LOG_TAG, msg2); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg2); + break; + default: + String msg3 = "BillingResult [" + billingResult.getResponseCode() + "]: " + billingResult.getDebugMessage(); + Log.d(LOG_TAG, msg3); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg3); + } + } + }; + + private void handlePurchase(Purchase purchase) { + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + // 支付完成 + if(!purchase.isAcknowledged()){ + mPurchase.put(purchase.getPurchaseToken(),purchase); + } + //验证签名 + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + boolean succ = verifyValidSignature(originalJson, signature); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + productInfo.put("signtureFlag", succ + ""); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_SUCCESS, productInfo.toString()); + }else{ + //未付款 + String msg = "purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + } + + //消耗 + public void consumeAsync(String purchaseToken){ + Purchase purchase = mPurchase.get(purchaseToken); + boolean isSub = false; + if(purchase != null){ + if(mSubList != null){ + for(SkuDetails Sku:mSubList){ + for ( String purchaseSku : purchase.getSkus() ) { + if (purchaseSku.equals(Sku.getSku())) { + isSub = true; + break; + } + } + } + } + } + if(isSub){ + handleSubsPurchase(purchase); + }else{ + final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken) + .build(); + mGoogleBillingClient.consumeAsync(consumeParams, (billingResult, purchaseToken1) -> { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "消耗成功..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); + } else { + Log.d(LOG_TAG, "消耗失败..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); + } + }); + } + } + + private void handleSubsPurchase(Purchase purchase) { + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + if (!purchase.isAcknowledged()) { + AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()) + .build(); + mGoogleBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() { + @Override + public void onAcknowledgePurchaseResponse(BillingResult billingResult) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "订阅成功..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); + } else { + Log.d(LOG_TAG, "订阅失败..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); + } + } + }); + } + } + } + + //查询缓存的购买交易 + public void queryUncompleteOrder(String payType){ + if (mGoogleBillingClient == null){ + String msg = "queryPurchases billingClient is null"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + return; + } + mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { + if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + } else { + //消耗 + JSONArray jsonArray = new JSONArray(); + for (Purchase purchase : list){ + //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + if (!purchase.isAcknowledged()){ + mPurchase.put(purchase.getPurchaseToken(), purchase); + //验证签名 + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("payType", payType); + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + boolean succ = verifyValidSignature(originalJson,signature); + productInfo.put("signtureFlag", String.valueOf(succ)); + productInfo.put("purchaseState", "1"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + }else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING){ + ArrayList skus = purchase.getSkus(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("purchaseState", "2"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + } + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, jsonArray.toString()); + } + }); + } + + + //查询缓存的訂閲状态 + public void querySubscribeOrder(String payType) { + if (mGoogleBillingClient == null) { + String msg = "queryPurchases billingClient is null"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + return; + } + mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { + if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + } else { + //消耗 + JSONArray jsonArray = new JSONArray(); + for (Purchase purchase : list){ + //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("payType", payType); + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + boolean succ = verifyValidSignature(originalJson,signature); + productInfo.put("signtureFlag", String.valueOf(succ)); + productInfo.put("purchaseState", "1"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + } + Log.d(LOG_TAG, "订阅状态查询 " + jsonArray.toString()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, jsonArray.toString()); + } + }); + } + + private boolean verifyValidSignature(String signedData, String signature) { + return Security.verifyPurchase(BASE_64_ENCODED_PUBLIC_KEY, signedData, signature); + } + + public void onDestroy(){ + if (mGoogleBillingClient != null && mGoogleBillingClient.isReady()){ + mGoogleBillingClient.endConnection(); + mGoogleBillingClient = null; + } + } +} diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java new file mode 100755 index 000000000..e26ee01be --- /dev/null +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java @@ -0,0 +1,96 @@ +package com.juzu.dz.third; + +import android.app.Activity; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.Scopes; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.Scope; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.juzu.dz.message.BFMessage; + +public class GoogleLogin { + private static volatile GoogleLogin sInstance; + private GoogleSignInClient mGoogleSignInClient; + private static final int REQUEST_CODE_GOOGLE_SIGN_IN = 1001; /* unique request id */ + private static final String server_client_token = "526230333982-j465cnveghnr5el3701rtsc38s3l08cg.apps.googleusercontent.com"; + + public static GoogleLogin getInstance() + { + if (sInstance == null) { + synchronized (GoogleLogin.class) { + if (sInstance == null) { + sInstance = new GoogleLogin(); + } + } + } + return sInstance; + } + + public void init(Activity activity){ + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestId() + .requestIdToken(server_client_token) + .requestServerAuthCode(server_client_token) + .requestScopes(new Scope(Scopes.PLUS_ME)) + .build(); + mGoogleSignInClient = GoogleSignIn.getClient(activity, gso); + } + + public void login(Activity activity) + { + Intent signInIntent = mGoogleSignInClient.getSignInIntent(); + activity.startActivityForResult(signInIntent, REQUEST_CODE_GOOGLE_SIGN_IN); + } + + public void logout(Activity activity) + { + mGoogleSignInClient.signOut().addOnCompleteListener(activity, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_SUCCESS, ""); + } + }); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (requestCode == REQUEST_CODE_GOOGLE_SIGN_IN) { + Task task = GoogleSignIn.getSignedInAccountFromIntent(data); + handleSignInResult(task); + } + } + + private void handleSignInResult(Task completedTask) { + try { + GoogleSignInAccount account = completedTask.getResult(ApiException.class); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_SUCCESS, createLoginInfo(account)); + } catch (ApiException e) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed e:" + e.getStatusCode() + " msg:" + e.getMessage()); + } + } + + private String createLoginInfo(GoogleSignInAccount account){ + String idToken = account.getIdToken(); + String uid = account.getId(); + JSONObject result = new JSONObject(); + try { + result.put("Token", idToken); + result.put("UserId", uid); + } catch (JSONException e) { + e.printStackTrace(); + } + return result.toString(); + } +} diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java new file mode 100755 index 000000000..4842382ca --- /dev/null +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java @@ -0,0 +1,148 @@ +package com.juzu.dz.third; + +import android.app.Activity; +import android.content.Intent; +import android.util.Log; + +import androidx.annotation.NonNull; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +// import com.google.firebase.messaging.FirebaseMessaging; +import com.juzu.dz.message.BFMessage; +import com.unity3d.player.UnityPlayer; + +import org.json.JSONException; +import org.json.JSONObject; + +public class GooglePlugin { + private static final String LOG_TAG = "GooglePlugin"; + private static GoogleLogin mGoogleLogin = null; + private static GoogleBilling mGoogleBilling = null; + private static Activity _activity; + + public static void init(Activity activity){ + _activity = activity; + } + + public static void initLogin() + { + if (mGoogleLogin == null) + { + mGoogleLogin = GoogleLogin.getInstance(); + mGoogleLogin.init(_activity); + } + } + + public static void initBilling() + { + if (mGoogleBilling == null) + { + mGoogleBilling = GoogleBilling.getInstance(); + mGoogleBilling.init(_activity); + } + } + + // 登录 + public static void login() + { + if (mGoogleLogin != null){ + mGoogleLogin.login(_activity); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed: not init"); + } + } + + // 登出 + public static void logout() + { + if (mGoogleLogin != null){ + mGoogleLogin.logout(_activity); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_FAILED, ""); + } + } + + public static void pay(String payType, String productId, String customMsg) + { + if (mGoogleBilling != null){ + mGoogleBilling.pay(_activity, payType, productId, customMsg); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, "billing not init"); + } + } + + public static void queryProductsInfo(String payType, String productJson) + { + if (mGoogleBilling != null){ + mGoogleBilling.queryProductsInfo(payType, productJson); + }else{ + sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, "billing not init"); + } + } + + public static void consumeAsync(String purchaseToken) + { + if (mGoogleBilling != null){ + mGoogleBilling.consumeAsync(purchaseToken); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, "billing not init"); + } + } + + public static void connectGoogleStore() + { + if (mGoogleBilling != null){ + mGoogleBilling.connectGoogleStore(); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, "billing not init"); + } + } + + public static void queryUncompleteOrder(String payType) + { + if (mGoogleBilling != null){ + mGoogleBilling.queryUncompleteOrder(payType); + }else{ + sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + } + } + + public static void querySubscribeOrder(String payType) + { + if (mGoogleBilling != null){ + mGoogleBilling.querySubscribeOrder(payType); + }else{ + sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + } + } + + public static void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (mGoogleLogin != null){ + mGoogleLogin.onActivityResult(requestCode, resultCode, data); + } + } + + public static void onDestroy() + { + if (mGoogleBilling != null){ + mGoogleBilling.onDestroy(); + } + } + + public static void getFirebaseToken() + { + } + + public static void sendMessageToUnity(int code, String msg){ + JSONObject data = new JSONObject(); + try { + data.put("head", code); + data.put("body", msg); + } catch (JSONException e) { + e.printStackTrace(); + } + Log.d(LOG_TAG, code + ":" + msg); + UnityPlayer.UnitySendMessage("SDKManager", "MsgFromAndroidOrIOS", data.toString()); + } +} \ No newline at end of file diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/Security.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/Security.java new file mode 100755 index 000000000..1dd7fa7d6 --- /dev/null +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/juzu/dz/third/Security.java @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.juzu.dz.third; +/* + * This class is an sample of how you can check to make sure your purchases on the device came + * from Google Play. Putting code like this on your server will provide additional protection. + *

+ * One thing that you may also wish to consider doing is caching purchase IDs to make replay + * attacks harder. The reason this code isn't just part of the library is to allow + * you to customize it (and rename it!) to make generic patching exploits more difficult. + */ + +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; + +/** + * Security-related methods. For a secure implementation, all of this code should be implemented on + * a server that communicates with the application on the device. + */ +class Security { + static final private String TAG = "IABUtil/Security"; + static final private String KEY_FACTORY_ALGORITHM = "RSA"; + static final private String SIGNATURE_ALGORITHM = "SHA1withRSA"; + + /** + * BASE_64_ENCODED_PUBLIC_KEY should be YOUR APPLICATION PUBLIC KEY. You currently get this + * from the Google Play developer console under the "Monetization Setup" category in the + * Licensing area. This build has been setup so that if you define base64EncodedPublicKey in + * your local.properties, it will be echoed into BuildConfig. + */ + + /** + * Verifies that the data was signed with the given signature + * + * @param signedData the signed JSON string (signed, not encrypted) + * @param signature the signature for the data, signed with the private key + */ + static public boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { + if ((TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) + || TextUtils.isEmpty(signature)) + ) { + Log.w(TAG, "Purchase verification failed: missing data."); + return false; + } + try { + PublicKey key = generatePublicKey(base64PublicKey); + return verify(key, signedData, signature); + } catch (IOException e) { + Log.e(TAG, "Error generating PublicKey from encoded key: " + e.getMessage()); + return false; + } + } + + /** + * Generates a PublicKey instance from a string containing the Base64-encoded public key. + * + * @param encodedPublicKey Base64-encoded public key + * @throws IOException if encoding algorithm is not supported or key specification + * is invalid + */ + static private PublicKey generatePublicKey(String encodedPublicKey) throws IOException { + try { + byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM); + return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); + } catch (NoSuchAlgorithmException e) { + // "RSA" is guaranteed to be available. + throw new RuntimeException(e); + } catch (InvalidKeySpecException e) { + String msg = "Invalid key specification: " + e; + Log.w(TAG, msg); + throw new IOException(msg); + } + } + + /** + * Verifies that the signature from the server matches the computed signature on the data. + * Returns true if the data is correctly signed. + * + * @param publicKey public key associated with the developer account + * @param signedData signed data from server + * @param signature server signature + * @return true if the data and signature match + */ + static private Boolean verify(PublicKey publicKey, String signedData, String signature) { + byte[] signatureBytes; + try { + signatureBytes = Base64.decode(signature, Base64.DEFAULT); + } catch (IllegalArgumentException e) { + Log.w(TAG, "Base64 decoding failed."); + return false; + } + try { + Signature signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM); + signatureAlgorithm.initVerify(publicKey); + signatureAlgorithm.update(signedData.getBytes()); + if (!signatureAlgorithm.verify(signatureBytes)) { + Log.w(TAG, "Signature verification failed..."); + return false; + } + return true; + } catch (NoSuchAlgorithmException e) { + // "RSA" is guaranteed to be available. + throw new RuntimeException(e); + } catch (InvalidKeyException e) { + Log.e(TAG, "Invalid key specification."); + } catch (SignatureException e) { + Log.e(TAG, "Signature exception."); + } + return false; + } +} diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java old mode 100644 new mode 100755 index cb9614b45..9a9eb71ca --- a/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java @@ -1,174 +1,174 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN -package com.unity3d.player; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.PixelFormat; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.os.Process; -// import android.os.Build; - -import com.juzu.dz.third.GooglePlugin; - -public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents -{ - protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code - - // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player - // The command line arguments are passed as a string, separated by spaces - // UnityPlayerActivity calls this from 'onCreate' - // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan - // See https://docs.unity3d.com/Manual/CommandLineArguments.html - // @param cmdLine the current command line arguments, may be null - // @return the modified command line string or null - protected String updateUnityCommandLineArguments(String cmdLine) - { - return cmdLine; - } - - // Setup activity layout - @Override protected void onCreate(Bundle savedInstanceState) - { - requestWindowFeature(Window.FEATURE_NO_TITLE); - super.onCreate(savedInstanceState); - - String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); - getIntent().putExtra("unity", cmdLine); - - mUnityPlayer = new UnityPlayer(this, this); - setContentView(mUnityPlayer); - mUnityPlayer.requestFocus(); - - GooglePlugin.init(this); - } - - // When Unity player unloaded move task to background - @Override public void onUnityPlayerUnloaded() { - moveTaskToBack(true); - } - - // Callback before Unity player process is killed - @Override public void onUnityPlayerQuitted() { - } - - @Override protected void onNewIntent(Intent intent) - { - // To support deep linking, we need to make sure that the client can get access to - // the last sent intent. The clients access this through a JNI api that allows them - // to get the intent set on launch. To update that after launch we have to manually - // replace the intent with the one caught here. - setIntent(intent); - mUnityPlayer.newIntent(intent); - } - - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - GooglePlugin.onActivityResult(requestCode, resultCode, data); - } - - // Quit Unity - @Override protected void onDestroy () - { - GooglePlugin.onDestroy(); - mUnityPlayer.destroy(); - super.onDestroy(); - } - - // If the activity is in multi window mode or resizing the activity is allowed we will use - // onStart/onStop (the visibility callbacks) to determine when to pause/resume. - // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve - // existing behavior. - @Override protected void onStop() - { - super.onStop(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - } - - @Override protected void onStart() - { - super.onStart(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - } - - // Pause Unity - @Override protected void onPause() - { - super.onPause(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - } - - // Resume Unity - @Override protected void onResume() - { - super.onResume(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - } - - // Low Memory Unity - @Override public void onLowMemory() - { - super.onLowMemory(); - mUnityPlayer.lowMemory(); - } - - // Trim Memory Unity - @Override public void onTrimMemory(int level) - { - super.onTrimMemory(level); - if (level == TRIM_MEMORY_RUNNING_CRITICAL) - { - mUnityPlayer.lowMemory(); - } - } - - // This ensures the layout will be correct. - @Override public void onConfigurationChanged(Configuration newConfig) - { - super.onConfigurationChanged(newConfig); - mUnityPlayer.configurationChanged(newConfig); - } - - // Notify Unity of the focus change. - @Override public void onWindowFocusChanged(boolean hasFocus) - { - super.onWindowFocusChanged(hasFocus); - mUnityPlayer.windowFocusChanged(hasFocus); - } - - // For some reason the multiple keyevent type is not supported by the ndk. - // Force event injection by overriding dispatchKeyEvent(). - @Override public boolean dispatchKeyEvent(KeyEvent event) - { - if (event.getAction() == KeyEvent.ACTION_MULTIPLE) - return mUnityPlayer.injectEvent(event); - return super.dispatchKeyEvent(event); - } - - // Pass any events not handled by (unfocused) views straight to UnityPlayer - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } - /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN +package com.unity3d.player; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.os.Process; +// import android.os.Build; + +import com.juzu.dz.third.GooglePlugin; + +public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents +{ + protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code + + // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player + // The command line arguments are passed as a string, separated by spaces + // UnityPlayerActivity calls this from 'onCreate' + // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan + // See https://docs.unity3d.com/Manual/CommandLineArguments.html + // @param cmdLine the current command line arguments, may be null + // @return the modified command line string or null + protected String updateUnityCommandLineArguments(String cmdLine) + { + return cmdLine; + } + + // Setup activity layout + @Override protected void onCreate(Bundle savedInstanceState) + { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState); + + String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); + getIntent().putExtra("unity", cmdLine); + + mUnityPlayer = new UnityPlayer(this, this); + setContentView(mUnityPlayer); + mUnityPlayer.requestFocus(); + + GooglePlugin.init(this); + } + + // When Unity player unloaded move task to background + @Override public void onUnityPlayerUnloaded() { + moveTaskToBack(true); + } + + // Callback before Unity player process is killed + @Override public void onUnityPlayerQuitted() { + } + + @Override protected void onNewIntent(Intent intent) + { + // To support deep linking, we need to make sure that the client can get access to + // the last sent intent. The clients access this through a JNI api that allows them + // to get the intent set on launch. To update that after launch we have to manually + // replace the intent with the one caught here. + setIntent(intent); + mUnityPlayer.newIntent(intent); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + GooglePlugin.onActivityResult(requestCode, resultCode, data); + } + + // Quit Unity + @Override protected void onDestroy () + { + GooglePlugin.onDestroy(); + mUnityPlayer.destroy(); + super.onDestroy(); + } + + // If the activity is in multi window mode or resizing the activity is allowed we will use + // onStart/onStop (the visibility callbacks) to determine when to pause/resume. + // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve + // existing behavior. + @Override protected void onStop() + { + super.onStop(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + } + + @Override protected void onStart() + { + super.onStart(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + } + + // Pause Unity + @Override protected void onPause() + { + super.onPause(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + } + + // Resume Unity + @Override protected void onResume() + { + super.onResume(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + } + + // Low Memory Unity + @Override public void onLowMemory() + { + super.onLowMemory(); + mUnityPlayer.lowMemory(); + } + + // Trim Memory Unity + @Override public void onTrimMemory(int level) + { + super.onTrimMemory(level); + if (level == TRIM_MEMORY_RUNNING_CRITICAL) + { + mUnityPlayer.lowMemory(); + } + } + + // This ensures the layout will be correct. + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + mUnityPlayer.configurationChanged(newConfig); + } + + // Notify Unity of the focus change. + @Override public void onWindowFocusChanged(boolean hasFocus) + { + super.onWindowFocusChanged(hasFocus); + mUnityPlayer.windowFocusChanged(hasFocus); + } + + // For some reason the multiple keyevent type is not supported by the ndk. + // Force event injection by overriding dispatchKeyEvent(). + @Override public boolean dispatchKeyEvent(KeyEvent event) + { + if (event.getAction() == KeyEvent.ACTION_MULTIPLE) + return mUnityPlayer.injectEvent(event); + return super.dispatchKeyEvent(event); + } + + // Pass any events not handled by (unfocused) views straight to UnityPlayer + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } + /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } +} diff --git a/BFVersions/android/dz_google_abb/unityLibrary/src/main/res/xml/network_security_config.xml b/BFVersions/android/dz_google_abb/unityLibrary/src/main/res/xml/network_security_config.xml old mode 100644 new mode 100755 index 3f9b9c92f..0edfdf604 --- a/BFVersions/android/dz_google_abb/unityLibrary/src/main/res/xml/network_security_config.xml +++ b/BFVersions/android/dz_google_abb/unityLibrary/src/main/res/xml/network_security_config.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/BFVersions/android/dz_google_apk/build.gradle b/BFVersions/android/dz_google_apk/build.gradle old mode 100644 new mode 100755 index 0b06040b2..f00e46780 --- a/BFVersions/android/dz_google_apk/build.gradle +++ b/BFVersions/android/dz_google_apk/build.gradle @@ -1,40 +1,42 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -buildscript { - repositories { - google() - jcenter() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:7.1.3' - classpath 'com.google.gms:google-services:4.3.13' - classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' - } -} - -allprojects { - buildscript { - repositories { - google() - jcenter() - } - -// dependencies { -// classpath 'com.android.tools.build:gradle:4.0.1' -// -// } - } - - repositories { - google() - jcenter() - flatDir { - dirs "${project(':unityLibrary').projectDir}/libs" - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +buildscript { + repositories { + google() + jcenter() + mavenCentral() + maven { url 'https://artifacts.applovin.com/android'; content { includeGroupByRegex 'com.applovin.*' } } + } + dependencies { + classpath 'com.android.tools.build:gradle:7.1.3' + classpath 'com.google.gms:google-services:4.3.13' + classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' + classpath 'com.applovin.quality:AppLovinQualityServiceGradlePlugin:+' + } +} + +allprojects { + buildscript { + repositories { + google() + jcenter() + } + +// dependencies { +// classpath 'com.android.tools.build:gradle:4.0.1' +// +// } + } + + repositories { + google() + jcenter() + flatDir { + dirs "${project(':unityLibrary').projectDir}/libs" + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/BFVersions/android/dz_google_apk/gradle.properties b/BFVersions/android/dz_google_apk/gradle.properties old mode 100644 new mode 100755 index 39b7fdd1d..130c0e6f8 --- a/BFVersions/android/dz_google_apk/gradle.properties +++ b/BFVersions/android/dz_google_apk/gradle.properties @@ -1,5 +1,6 @@ -org.gradle.jvmargs=-Xmx4096M -org.gradle.parallel=true -android.useAndroidX=true -android.enableJetifier=true -unityStreamingAssets=.unity3d, .bytes, .ab, UnityServicesProjectConfiguration.json \ No newline at end of file +org.gradle.jvmargs=-Xmx4096M +org.gradle.parallel=true +android.useAndroidX=true +android.enableJetifier=true +unityStreamingAssets=.unity3d, .bytes, .ab, UnityServicesProjectConfiguration.json +unityTemplateVersion=4 \ No newline at end of file diff --git a/BFVersions/android/dz_google_apk/gradle/wrapper/gradle-wrapper.properties b/BFVersions/android/dz_google_apk/gradle/wrapper/gradle-wrapper.properties new file mode 100755 index 000000000..abff0a8d3 --- /dev/null +++ b/BFVersions/android/dz_google_apk/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,5 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip diff --git a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/AndroidManifest.xml b/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/AndroidManifest.xml deleted file mode 100644 index 6ad08dd83..000000000 --- a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/AndroidManifest.xml +++ /dev/null @@ -1,12 +0,0 @@ - - - - - - - - - - - - \ No newline at end of file diff --git a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/build.gradle b/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/build.gradle deleted file mode 100644 index c4321566e..000000000 --- a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/build.gradle +++ /dev/null @@ -1,28 +0,0 @@ -apply plugin: 'android-library' - -dependencies { - implementation fileTree(dir: 'bin', include: ['*.jar']) - implementation fileTree(dir: 'libs', include: ['*.jar']) -} - -android { - sourceSets { - main { - manifest.srcFile 'AndroidManifest.xml' - //java.srcDirs = ['src'] - res.srcDirs = ['res'] - assets.srcDirs = ['assets'] - jniLibs.srcDirs = ['libs'] - } - } - - compileSdkVersion 34 - buildToolsVersion '30.0.2' - defaultConfig { - targetSdkVersion 34 - } - - lintOptions { - abortOnError false - } -} diff --git a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/libs/IronSource-bridge.jar b/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/libs/IronSource-bridge.jar deleted file mode 100644 index 44dcadb64..000000000 Binary files a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/libs/IronSource-bridge.jar and /dev/null differ diff --git a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/project.properties b/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/project.properties deleted file mode 100644 index 37b95eded..000000000 --- a/BFVersions/android/dz_google_apk/unityLibrary/IronSource.androidlib/project.properties +++ /dev/null @@ -1,2 +0,0 @@ -target=android-9 -android.library=true \ No newline at end of file diff --git a/BFVersions/android/dz_google_apk/unityLibrary/build.gradle b/BFVersions/android/dz_google_apk/unityLibrary/build.gradle old mode 100644 new mode 100755 index 51fcce36b..6217aa40d --- a/BFVersions/android/dz_google_apk/unityLibrary/build.gradle +++ b/BFVersions/android/dz_google_apk/unityLibrary/build.gradle @@ -1,206 +1,203 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.library' - - -// Android Resolver Repos Start -([rootProject] + (rootProject.subprojects as List)).each { project -> - project.repositories { - def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/") - maven { - url "https://maven.google.com" - } - maven { - url "https://android-sdk.is.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:9, Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:16, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:16, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8, Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:8, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:16, Assets/IronSource/Editor/ISFyberAdapterDependencies.xml:16, Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:48, Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:8, Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:8, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8, Assets/IronSource/Editor/ISVungleAdapterDependencies.xml:16, Assets/IronSourceAdQuality/Editor/IronSourceAdQualityDependencies.xml:9, Assets/IronSourceAdQuality/Editor/IronSourceAdQualityDependencies.xml:17 - } - maven { - url "https://maven.google.com/" // Assets/IronSource/Editor/IronSourceSDKDependencies.xml:17, Assets/IronSource/Editor/IronSourceSDKDependencies.xml:25, Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:8, Assets/IronSource/Editor/ISAdMobAdapterDependencies.xml:8, Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15, Assets/IronSource/Editor/ISFacebookAdapterDependencies.xml:8, Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:40, Assets/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 - } - maven { - url "https://cboost.jfrog.io/artifactory/chartboost-ads/" // Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:15 - } - maven { - url "https://repo.maven.apache.org/maven2/" // Assets/IronSource/Editor/ISFyberAdapterDependencies.xml:8 - } - maven { - url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea/" // Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:8, Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:16, Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:24, Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:32 - } - maven { - url "https://artifact.bytedance.com/repository/pangle/" // Assets/IronSource/Editor/ISPangleAdapterDependencies.xml:15 - } - maven { - url "https://sdk.tapjoy.com/" // Assets/IronSource/Editor/ISTapJoyAdapterDependencies.xml:15 - } - maven { - url "https://jitpack.io/" // Assets/IronSource/Editor/ISVungleAdapterDependencies.xml:8 - } - mavenLocal() - jcenter() - mavenCentral() - } -} -// Android Resolver Repos End - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:multidex:1.0.3' - - implementation(name: 'screenutils-release', ext:'aar') - implementation(name: 'ThinkingSDK', ext:'aar') - implementation(name: 'UnityUtils-release', ext:'aar') - implementation(name: 'facebook-android-wrapper-15.1.0', ext:'aar') - implementation 'com.google.android.gms:play-services-auth:20.1.0' - implementation "com.android.billingclient:billing:6.2.1" - - // firebase - implementation 'com.google.firebase:firebase-analytics:21.1.0' - implementation 'com.google.firebase:firebase-crashlytics:18.2.12' - implementation 'com.google.firebase:firebase-messaging:23.0.8' - - // adjust - implementation(name: 'adjust-android-signaturev2-v2.15.10-s2', ext:'aar') - - implementation project('IronSource.androidlib') - - // Android Resolver Dependencies Start - implementation 'androidx.recyclerview:recyclerview:1.2.1' // Assets/IronSource/Editor/ISMintegralAdapterDependencies.xml:40 - implementation 'com.adcolony:sdk:4.8.0' // Assets/IronSource/Editor/ISAdColonyAdapterDependencies.xml:8 - implementation 'com.android.installreferrer:installreferrer:2.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:10 - implementation 'com.android.support:appcompat-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:cardview-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:customtabs:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.android.support:support-v4:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency - implementation 'com.applovin:applovin-sdk:11.10.1' // Assets/IronSource/Editor/ISAppLovinAdapterDependencies.xml:15 - implementation 'com.appsflyer:af-android-sdk:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:6 - implementation 'com.appsflyer:unity-wrapper:6.4.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:8 - implementation 'com.appsflyer:adrevenue:6.5.4' // Assets/ThirdParty/AppsFlyerAdrevenue/Editor/AppsFlyerAdRevenueDependencies.xml:4 - implementation 'com.appsflyer:unity-adrevenue-generic-wrapper:6.5.4' // Assets/ThirdParty/AppsFlyerAdrevenue/Editor/AppsFlyerAdRevenueDependencies.xml:5 - implementation 'com.chartboost:chartboost-sdk:9.3.1' // Assets/IronSource/Editor/ISChartboostAdapterDependencies.xml:15 - implementation 'com.facebook.android:audience-network-sdk:6.16.0' // Assets/ThirdParty/IronSource/Editor/ISFacebookAdapterDependencies.xml:8 - implementation 'com.facebook.android:facebook-applinks:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:6 - implementation 'com.facebook.android:facebook-core:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:5 - implementation 'com.facebook.android:facebook-gamingservices:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:9 - implementation 'com.facebook.android:facebook-login:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:7 - implementation 'com.facebook.android:facebook-share:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:8 - implementation 'com.fyber:marketplace-sdk:8.2.4' // Assets/ThirdParty/IronSource/Editor/ISFyberAdapterDependencies.xml:8 - implementation 'com.google.android.gms:play-services-ads:22.2.0' // Assets/ThirdParty/IronSource/Editor/ISAdMobAdapterDependencies.xml:8 - implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' // Assets/ThirdParty/IronSource/Editor/IronSourceSDKDependencies.xml:17 - implementation 'com.google.android.gms:play-services-basement:18.1.0' // Assets/ThirdParty/IronSource/Editor/IronSourceSDKDependencies.xml:25 - implementation 'com.ironsource.adapters:adcolonyadapter:4.3.15' // Assets/ThirdParty/IronSource/Editor/ISAdColonyAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:admobadapter:4.3.39' // Assets/ThirdParty/IronSource/Editor/ISAdMobAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:applovinadapter:4.3.39' // Assets/ThirdParty/IronSource/Editor/ISAppLovinAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:chartboostadapter:4.3.12' // Assets/ThirdParty/IronSource/Editor/ISChartboostAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:facebookadapter:4.3.45' // Assets/ThirdParty/IronSource/Editor/ISFacebookAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:fyberadapter:4.3.28' // Assets/ThirdParty/IronSource/Editor/ISFyberAdapterDependencies.xml:16 - implementation 'com.ironsource.adapters:mintegraladapter:4.3.19' // Assets/ThirdParty/IronSource/Editor/ISMintegralAdapterDependencies.xml:48 - implementation 'com.ironsource.adapters:pangleadapter:4.3.22' // Assets/ThirdParty/IronSource/Editor/ISPangleAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:tapjoyadapter:4.1.25' // Assets/ThirdParty/IronSource/Editor/ISTapJoyAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:unityadsadapter:4.3.33' // Assets/ThirdParty/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:8 - implementation 'com.ironsource.adapters:vungleadapter:4.3.22' // Assets/ThirdParty/IronSource/Editor/ISVungleAdapterDependencies.xml:16 - implementation 'com.ironsource.sdk:mediationsdk:7.5.1' // Assets/ThirdParty/IronSource/Editor/IronSourceSDKDependencies.xml:9 - implementation 'com.mbridge.msdk.oversea:mbbanner:16.5.21' // Assets/ThirdParty/IronSource/Editor/ISMintegralAdapterDependencies.xml:24 - implementation 'com.mbridge.msdk.oversea:mbbid:16.5.21' // Assets/ThirdParty/IronSource/Editor/ISMintegralAdapterDependencies.xml:32 - implementation 'com.mbridge.msdk.oversea:newinterstitial:16.5.21' // Assets/ThirdParty/IronSource/Editor/ISMintegralAdapterDependencies.xml:8 - implementation 'com.mbridge.msdk.oversea:reward:16.5.21' // Assets/ThirdParty/IronSource/Editor/ISMintegralAdapterDependencies.xml:16 - implementation 'com.pangle.global:ads-sdk:5.5.0.5' // Assets/ThirdParty/IronSource/Editor/ISPangleAdapterDependencies.xml:15 - implementation 'com.parse.bolts:bolts-android:1.4.0' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:4 - implementation 'com.tapjoy:tapjoy-android-sdk:13.0.1' // Assets/ThirdParty/IronSource/Editor/ISTapJoyAdapterDependencies.xml:15 - implementation 'com.unity3d.ads:unity-ads:4.9.1' // Assets/ThirdParty/IronSource/Editor/ISUnityAdsAdapterDependencies.xml:15 - implementation 'com.vungle:vungle-ads:7.0.0' // Assets/ThirdParty/IronSource/Editor/ISVungleAdapterDependencies.xml:8 -// Android Resolver Dependencies End - constraints { - implementation('androidx.work:work-runtime:2.7.0') { - because '''androidx.work:work-runtime:2.1.0 pulled from - play-services-ads has a bug using PendingIntent without - FLAG_IMMUTABLE or FLAG_MUTABLE and will fail in Apps - targeting S+.''' - } - } -} - -android { - compileSdkVersion 34 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - - defaultConfig { - minSdkVersion 24 - targetSdkVersion 34 - ndk { - abiFilters 'armeabi-v7a', 'arm64-v8a' - } - versionCode 1 - versionName '0.1.0' - consumerProguardFiles 'proguard-unity.txt' - } - - lintOptions { - abortOnError false - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - doNotStrip '*/arm64-v8a/*.so' - } -} - -def getSdkDir() { - Properties local = new Properties() - local.load(new FileInputStream("${rootDir}/local.properties")) - return local.getProperty('sdk.dir') -} - -def BuildIl2Cpp(String workingDir, String targetDirectory, String architecture, String abi, String configuration) { - exec { - commandLine(workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/netcoreapp3.1/il2cpp", - "--compile-cpp", - "--libil2cpp-static", - "--platform=Android", - "--architecture=" + architecture, - "--configuration=" + configuration, - "--outputpath=" + workingDir + targetDirectory + abi + "/libil2cpp.so", - "--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/external/bdwgc/include", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/include", - "--tool-chain-path=" + android.ndkDirectory, - "--map-file-parser=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/MapFileParser/MapFileParser.exe", - "--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput", - "--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi, - "--dotnetprofile=unityaot") - environment "ANDROID_SDK_ROOT", getSdkDir() - } - delete workingDir + targetDirectory + abi + "/libil2cpp.sym.so" - ant.move(file: workingDir + targetDirectory + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") -} - -android { - task BuildIl2CppTask { - doLast { - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARMv7', 'armeabi-v7a', 'Release'); - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARM64', 'arm64-v8a', 'Release'); - } - } - afterEvaluate { - if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) - project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask - if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) - project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask - } - sourceSets { - main { - jni.srcDirs = ["src/main/Il2CppOutputProject"] - } - } -} - - - +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.library' + + +// Android Resolver Repos Start +([rootProject] + (rootProject.subprojects as List)).each { project -> + project.repositories { + def unityProjectPath = $/file:///**DIR_UNITYPROJECT**/$.replace("\\", "/") + maven { + url "https://maven.google.com" + } + maven { + url "https://verve.jfrog.io/artifactory/verve-gradle-release" // Assets/ThirdParty/MaxSdk/Mediation/Verve/Editor/Dependencies.xml:7 + } + maven { + url "https://artifactory.bidmachine.io/bidmachine" // Assets/ThirdParty/MaxSdk/Mediation/BidMachine/Editor/Dependencies.xml:8 + } + maven { + url "https://cboost.jfrog.io/artifactory/chartboost-ads/" // Assets/ThirdParty/MaxSdk/Mediation/Chartboost/Editor/Dependencies.xml:8 + } + maven { + url "https://android-sdk.is.com/" // Assets/ThirdParty/MaxSdk/Mediation/IronSource/Editor/Dependencies.xml:8 + } + maven { + url "https://dl-maven-android.mintegral.com/repository/mbridge_android_sdk_oversea" // Assets/ThirdParty/MaxSdk/Mediation/Mintegral/Editor/Dependencies.xml:8 + } + maven { + url "https://artifact.bytedance.com/repository/pangle" // Assets/ThirdParty/MaxSdk/Mediation/ByteDance/Editor/Dependencies.xml:8 + } + maven { url "../Upload-TaurusX" } + maven { + url "https://bitbucket.org/sdkcenter/sdkcenter/raw/release" + } + mavenLocal() + jcenter() + mavenCentral() + } +} +// Android Resolver Repos End + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:multidex:1.0.3' + // IAB TCF Decoder + implementation("com.iabtcf:iabtcf-decoder:2.0.10") + + implementation(name: 'screenutils-release', ext:'aar') + implementation(name: 'ThinkingSDK', ext:'aar') + implementation(name: 'UnityUtils-release', ext:'aar') + implementation(name: 'LofeltHaptics', ext:'aar') + implementation(name: 'facebook-android-wrapper-15.1.0', ext:'aar') + implementation(name: 'applovin-max-unity-plugin', ext:'aar') + implementation "com.android.billingclient:billing:6.2.1" + implementation 'com.google.android.gms:play-services-auth:20.1.0' + implementation 'com.google.android.play:review:2.0.1' + +// Android Resolver Dependencies Start + implementation 'com.google.firebase:firebase-analytics:21.4.0' + implementation 'com.google.firebase:firebase-crashlytics:18.5.0' + implementation 'com.google.firebase:firebase-messaging:23.3.0' + implementation 'androidx.recyclerview:recyclerview:1.2.1' // Assets/ThirdParty/MaxSdk/Mediation/Mintegral/Editor/Dependencies.xml:9 + implementation 'com.android.installreferrer:installreferrer:2.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:10 + implementation 'com.android.support:appcompat-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.android.support:cardview-v7:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.android.support:customtabs:28.+' // Assets/ThirdParty/MaxSdk/Mediation/InMobi/Editor/Dependencies.xml:7 + implementation 'com.android.support:recyclerview-v7:28.+' // Assets/ThirdParty/MaxSdk/Mediation/InMobi/Editor/Dependencies.xml:6 + implementation 'com.android.support:support-v4:25.3.1' // Facebook.Unity.Editor.AndroidSupportLibraryResolver.addSupportLibraryDependency + implementation 'com.applovin.mediation:bidmachine-adapter:3.2.1.0' // Assets/ThirdParty/MaxSdk/Mediation/BidMachine/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:bigoads-adapter:5.2.1.0' // Assets/ThirdParty/MaxSdk/Mediation/BigoAds/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:bytedance-adapter:6.5.0.8.1' // Assets/ThirdParty/MaxSdk/Mediation/ByteDance/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:chartboost-adapter:9.8.3.0' // Assets/ThirdParty/MaxSdk/Mediation/Chartboost/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:facebook-adapter:[6.19.0.2]' // Assets/ThirdParty/MaxSdk/Mediation/Facebook/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:fyber-adapter:8.3.6.1' // Assets/ThirdParty/MaxSdk/Mediation/Fyber/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:google-adapter:[24.2.0.0]' // Assets/ThirdParty/MaxSdk/Mediation/Google/Editor/Dependencies.xml:5 + implementation 'com.applovin.mediation:google-ad-manager-adapter:[24.2.0.0]' // Assets/ThirdParty/MaxSdk/Mediation/GoogleAdManager/Editor/Dependencies.xml:5 + implementation 'com.applovin.mediation:inmobi-adapter:10.8.2.0' // Assets/ThirdParty/MaxSdk/Mediation/InMobi/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:ironsource-adapter:8.7.0.0.0' // Assets/ThirdParty/MaxSdk/Mediation/IronSource/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:line-adapter:2025.1.10.1' // Assets/ThirdParty/MaxSdk/Mediation/Line/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:mobilefuse-adapter:1.9.0.0' // Assets/ThirdParty/MaxSdk/Mediation/MobileFuse/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:moloco-adapter:3.8.0.0' // Assets/ThirdParty/MaxSdk/Mediation/Moloco/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:mytarget-adapter:5.27.1.2' // Assets/ThirdParty/MaxSdk/Mediation/MyTarget/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:unityads-adapter:4.14.1.0' // Assets/ThirdParty/MaxSdk/Mediation/UnityAds/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:verve-adapter:3.3.0.0' // Assets/ThirdParty/MaxSdk/Mediation/Verve/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:vungle-adapter:7.4.3.2' // Assets/ThirdParty/MaxSdk/Mediation/Vungle/Editor/Dependencies.xml:4 + implementation 'com.applovin.mediation:mintegral-adapter:16.9.61.0' // Assets/ThirdParty/MaxSdk/Mediation/Mintegral/Editor/Dependencies.xml:8 + implementation 'com.applovin.mediation:yandex-adapter:7.9.0.1' // Assets/ThirdParty/MaxSdk/Mediation/Yandex/Editor/Dependencies.xml:4 + implementation "com.taurusx.tax:ads:1.5.4" // Assets/ThirdParty/MaxSdk/Mediation/TaurusX/Editor/Dependencies.xml:4 + implementation "com.applovin.mediation:taurusXAdapters:1.3.0.1" + implementation 'com.applovin:applovin-sdk:13.1.0' // Assets/ThirdParty/MaxSdk/AppLovin/Editor/Dependencies.xml:4 + implementation 'com.appsflyer:adrevenue:6.9.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerAdRevenueDependencies.xml:4 + implementation 'com.appsflyer:unity-adrevenue-generic-wrapper:6.9.1' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerAdRevenueDependencies.xml:5 + implementation 'com.appsflyer:af-android-sdk:6.13.0' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:6 + implementation 'com.appsflyer:unity-wrapper:6.13.10' // Assets/ThirdParty/AppsFlyer/Editor/AppsFlyerDependencies.xml:8 + implementation 'com.facebook.android:facebook-applinks:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:6 + implementation 'com.facebook.android:facebook-core:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:5 + implementation 'com.facebook.android:facebook-gamingservices:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:9 + implementation 'com.facebook.android:facebook-login:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:7 + implementation 'com.facebook.android:facebook-share:[15.1,16)' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:8 + implementation 'com.google.android.gms:play-services-base:16.1.0' // Assets/ThirdParty/MaxSdk/Mediation/Chartboost/Editor/Dependencies.xml:9 + implementation 'com.parse.bolts:bolts-android:1.4.0' // Assets/ThirdParty/FacebookSDK/Plugins/Editor/Dependencies.xml:4 + implementation 'com.squareup.picasso:picasso:2.71828' // Assets/ThirdParty/MaxSdk/Mediation/InMobi/Editor/Dependencies.xml:5 + implementation 'com.google.android.ump:user-messaging-platform:2.1.0' +// Android Resolver Dependencies End +} + +android { + compileSdkVersion 34 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 34 + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a' + } + versionCode 1 + versionName '0.1.0' + consumerProguardFiles 'proguard-unity.txt' + } + + lintOptions { + abortOnError false + } + + aaptOptions { + noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + doNotStrip '*/arm64-v8a/*.so' + } +} + +def getSdkDir() { + Properties local = new Properties() + local.load(new FileInputStream("${rootDir}/local.properties")) + return local.getProperty('sdk.dir') +} + +def BuildIl2Cpp(String workingDir, String configuration, String architecture, String abi, String[] staticLibraries) { + def commandLineArgs = [] + commandLineArgs.add("--compile-cpp") + commandLineArgs.add("--platform=Android") + commandLineArgs.add("--architecture=" + architecture) + commandLineArgs.add("--outputpath=" + workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.so") + commandLineArgs.add("--libil2cpp-static") + commandLineArgs.add("--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi) + commandLineArgs.add("--incremental-g-c-time-slice=3") + commandLineArgs.add("--configuration=" + configuration) + commandLineArgs.add("--dotnetprofile=unityaot-linux") + commandLineArgs.add("--profiler-report") + commandLineArgs.add("--profiler-output-file=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_conv.traceevents") + commandLineArgs.add("--print-command-line") + commandLineArgs.add("--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput") + commandLineArgs.add("--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache") + commandLineArgs.add("--tool-chain-path=" + android.ndkDirectory) + staticLibraries.eachWithIndex {fileName, i-> + commandLineArgs.add("--additional-libraries=" + workingDir + "/src/main/jniStaticLibs/" + abi + "/" + fileName) + } + def executableExtension = "" + if (org.gradle.internal.os.OperatingSystem.current().isWindows()) { + executableExtension = ".exe" + commandLineArgs = commandLineArgs*.replace('\"', '\\\"') + } + exec { + executable workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/il2cpp" + executableExtension + args commandLineArgs + environment "ANDROID_SDK_ROOT", getSdkDir() + } + delete workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.sym.so" + ant.move(file: workingDir + "/src/main/jniLibs/" + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") +} + +android { + task BuildIl2CppTask { + doLast { + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Release', 'armv7', 'armeabi-v7a', [ ] as String[]); + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), 'Release', 'arm64', 'arm64-v8a', [ ] as String[]); + } + } + afterEvaluate { + if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) + project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask + if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) + project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask + } + sourceSets { + main { + jni.srcDirs = ["src/main/Il2CppOutputProject"] + } + } +} + + + diff --git a/BFVersions/android/dz_google_apk/unityLibrary/src/main/AndroidManifest.xml b/BFVersions/android/dz_google_apk/unityLibrary/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 095438cb6..cb32332d8 --- a/BFVersions/android/dz_google_apk/unityLibrary/src/main/AndroidManifest.xml +++ b/BFVersions/android/dz_google_apk/unityLibrary/src/main/AndroidManifest.xml @@ -1,79 +1,87 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - REPLACE_BUILD_ID - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BFVersions/android/dz_google_apk/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java b/BFVersions/android/dz_google_apk/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java old mode 100644 new mode 100755 index ca3396058..e08cb5c0c --- a/BFVersions/android/dz_google_apk/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java +++ b/BFVersions/android/dz_google_apk/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java @@ -1,188 +1,179 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN -package com.unity3d.player; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.PixelFormat; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.os.Process; -// import android.os.Build; - -// import com.chartboost.sdk.Chartboost; -import com.juzu.dz.third.GooglePlugin; -import com.ironsource.mediationsdk.IronSource; - -public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents -{ - protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code - - // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player - // The command line arguments are passed as a string, separated by spaces - // UnityPlayerActivity calls this from 'onCreate' - // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan - // See https://docs.unity3d.com/Manual/CommandLineArguments.html - // @param cmdLine the current command line arguments, may be null - // @return the modified command line string or null - protected String updateUnityCommandLineArguments(String cmdLine) - { - return cmdLine; - } - - // Setup activity layout - @Override protected void onCreate(Bundle savedInstanceState) - { - requestWindowFeature(Window.FEATURE_NO_TITLE); - super.onCreate(savedInstanceState); - - String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); - getIntent().putExtra("unity", cmdLine); - - mUnityPlayer = new UnityPlayer(this, this); - setContentView(mUnityPlayer); - mUnityPlayer.requestFocus(); - - GooglePlugin.init(this); - } - - // When Unity player unloaded move task to background - @Override public void onUnityPlayerUnloaded() { - moveTaskToBack(true); - } - - // Callback before Unity player process is killed - @Override public void onUnityPlayerQuitted() { - } - - @Override protected void onNewIntent(Intent intent) - { - // To support deep linking, we need to make sure that the client can get access to - // the last sent intent. The clients access this through a JNI api that allows them - // to get the intent set on launch. To update that after launch we have to manually - // replace the intent with the one caught here. - setIntent(intent); - mUnityPlayer.newIntent(intent); - } - - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - GooglePlugin.onActivityResult(requestCode, resultCode, data); - } - - // Quit Unity - @Override protected void onDestroy () - { - GooglePlugin.onDestroy(); - mUnityPlayer.destroy(); - super.onDestroy(); - } - - // If the activity is in multi window mode or resizing the activity is allowed we will use - // onStart/onStop (the visibility callbacks) to determine when to pause/resume. - // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve - // existing behavior. - @Override protected void onStop() - { - super.onStop(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - } - - @Override protected void onStart() - { - super.onStart(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - } - - // Pause Unity - @Override protected void onPause() - { - super.onPause(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - IronSource.onPause(this); - } - - // Resume Unity - @Override protected void onResume() - { - super.onResume(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - IronSource.onResume(this); - } - - @Override - public void onBackPressed() { - // If an interstitial is on screen, close it. - // if (Chartboost.onBackPressed()) { - // return; - // } else { - // super.onBackPressed(); - // } - } - - // Low Memory Unity - @Override public void onLowMemory() - { - super.onLowMemory(); - mUnityPlayer.lowMemory(); - } - - // Trim Memory Unity - @Override public void onTrimMemory(int level) - { - super.onTrimMemory(level); - if (level == TRIM_MEMORY_RUNNING_CRITICAL) - { - mUnityPlayer.lowMemory(); - } - } - - // This ensures the layout will be correct. - @Override public void onConfigurationChanged(Configuration newConfig) - { - super.onConfigurationChanged(newConfig); - mUnityPlayer.configurationChanged(newConfig); - } - - // Notify Unity of the focus change. - @Override public void onWindowFocusChanged(boolean hasFocus) - { - super.onWindowFocusChanged(hasFocus); - mUnityPlayer.windowFocusChanged(hasFocus); - } - - // For some reason the multiple keyevent type is not supported by the ndk. - // Force event injection by overriding dispatchKeyEvent(). - @Override public boolean dispatchKeyEvent(KeyEvent event) - { - if (event.getAction() == KeyEvent.ACTION_MULTIPLE) - return mUnityPlayer.injectEvent(event); - return super.dispatchKeyEvent(event); - } - - // Pass any events not handled by (unfocused) views straight to UnityPlayer - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } - /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN +package com.unity3d.player; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.os.Process; + +// import com.chartboost.sdk.Chartboost; +import com.juzu.dz.third.GooglePlugin; +// import com.ironsource.mediationsdk.IronSource; + +public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents +{ + protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code + + // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player + // The command line arguments are passed as a string, separated by spaces + // UnityPlayerActivity calls this from 'onCreate' + // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan + // See https://docs.unity3d.com/Manual/CommandLineArguments.html + // @param cmdLine the current command line arguments, may be null + // @return the modified command line string or null + protected String updateUnityCommandLineArguments(String cmdLine) + { + return cmdLine; + } + + // Setup activity layout + @Override protected void onCreate(Bundle savedInstanceState) + { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState); + + String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); + getIntent().putExtra("unity", cmdLine); + + mUnityPlayer = new UnityPlayer(this, this); + setContentView(mUnityPlayer); + mUnityPlayer.requestFocus(); + + GooglePlugin.init(this); + } + + // When Unity player unloaded move task to background + @Override public void onUnityPlayerUnloaded() { + moveTaskToBack(true); + } + + // Callback before Unity player process is killed + @Override public void onUnityPlayerQuitted() { + } + + @Override protected void onNewIntent(Intent intent) + { + // To support deep linking, we need to make sure that the client can get access to + // the last sent intent. The clients access this through a JNI api that allows them + // to get the intent set on launch. To update that after launch we have to manually + // replace the intent with the one caught here. + setIntent(intent); + mUnityPlayer.newIntent(intent); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + GooglePlugin.onActivityResult(requestCode, resultCode, data); + } + + // Quit Unity + @Override protected void onDestroy () + { + GooglePlugin.onDestroy(); + mUnityPlayer.destroy(); + super.onDestroy(); + } + + // If the activity is in multi window mode or resizing the activity is allowed we will use + // onStart/onStop (the visibility callbacks) to determine when to pause/resume. + // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve + // existing behavior. + @Override protected void onStop() + { + super.onStop(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + } + + @Override protected void onStart() + { + super.onStart(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + } + + // Pause Unity + @Override protected void onPause() + { + super.onPause(); + + MultiWindowSupport.saveMultiWindowMode(this); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + // IronSource.onPause(this); + } + + // Resume Unity + @Override protected void onResume() + { + super.onResume(); + + if (MultiWindowSupport.getAllowResizableWindow(this) && !MultiWindowSupport.isMultiWindowModeChangedToTrue(this)) + return; + + mUnityPlayer.resume(); + // IronSource.onResume(this); + } + + // Low Memory Unity + @Override public void onLowMemory() + { + super.onLowMemory(); + mUnityPlayer.lowMemory(); + } + + // Trim Memory Unity + @Override public void onTrimMemory(int level) + { + super.onTrimMemory(level); + if (level == TRIM_MEMORY_RUNNING_CRITICAL) + { + mUnityPlayer.lowMemory(); + } + } + + // This ensures the layout will be correct. + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + mUnityPlayer.configurationChanged(newConfig); + } + + // Notify Unity of the focus change. + @Override public void onWindowFocusChanged(boolean hasFocus) + { + super.onWindowFocusChanged(hasFocus); + mUnityPlayer.windowFocusChanged(hasFocus); + } + + // For some reason the multiple keyevent type is not supported by the ndk. + // Force event injection by overriding dispatchKeyEvent(). + @Override public boolean dispatchKeyEvent(KeyEvent event) + { + if (event.getAction() == KeyEvent.ACTION_MULTIPLE) + return mUnityPlayer.injectEvent(event); + return super.dispatchKeyEvent(event); + } + + // Pass any events not handled by (unfocused) views straight to UnityPlayer + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } + /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } +} diff --git a/BFVersions/android/dz_google_apk/unityLibrary/src/main/res/xml/network_security_config.xml b/BFVersions/android/dz_google_apk/unityLibrary/src/main/res/xml/network_security_config.xml old mode 100644 new mode 100755 index 3f9b9c92f..0edfdf604 --- a/BFVersions/android/dz_google_apk/unityLibrary/src/main/res/xml/network_security_config.xml +++ b/BFVersions/android/dz_google_apk/unityLibrary/src/main/res/xml/network_security_config.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/BFVersions/android/dz_release/build.gradle b/BFVersions/android/dz_release/build.gradle old mode 100644 new mode 100755 index 2f61422bd..2e1ead0e0 --- a/BFVersions/android/dz_release/build.gradle +++ b/BFVersions/android/dz_release/build.gradle @@ -1,40 +1,40 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -buildscript { - repositories { - google() - jcenter() - mavenCentral() - } - dependencies { - classpath 'com.android.tools.build:gradle:4.0.1' - classpath 'com.google.gms:google-services:4.3.13' - // classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' - } -} - -allprojects { - buildscript { - repositories { - google() - jcenter() - } - -// dependencies { -// classpath 'com.android.tools.build:gradle:4.0.1' -// -// } - } - - repositories { - google() - jcenter() - flatDir { - dirs "${project(':unityLibrary').projectDir}/libs" - } - } -} - -task clean(type: Delete) { - delete rootProject.buildDir -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +buildscript { + repositories { + google() + jcenter() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.1' + classpath 'com.google.gms:google-services:4.3.13' + // classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.1' + } +} + +allprojects { + buildscript { + repositories { + google() + jcenter() + } + +// dependencies { +// classpath 'com.android.tools.build:gradle:4.0.1' +// +// } + } + + repositories { + google() + jcenter() + flatDir { + dirs "${project(':unityLibrary').projectDir}/libs" + } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} diff --git a/BFVersions/android/dz_release/gradle.properties b/BFVersions/android/dz_release/gradle.properties old mode 100644 new mode 100755 index 58e8481f1..0521300d1 --- a/BFVersions/android/dz_release/gradle.properties +++ b/BFVersions/android/dz_release/gradle.properties @@ -1,6 +1,6 @@ -org.gradle.jvmargs=-Xmx4096M -org.gradle.parallel=true -android.enableR8=false -android.useAndroidX=true -android.enableJetifier=true +org.gradle.jvmargs=-Xmx4096M +org.gradle.parallel=true +android.enableR8=false +android.useAndroidX=true +android.enableJetifier=true unityStreamingAssets=.unity3d, .bytes, .ab \ No newline at end of file diff --git a/BFVersions/android/dz_release/unityLibrary/build.gradle b/BFVersions/android/dz_release/unityLibrary/build.gradle old mode 100644 new mode 100755 index e01f9a38b..30a1149be --- a/BFVersions/android/dz_release/unityLibrary/build.gradle +++ b/BFVersions/android/dz_release/unityLibrary/build.gradle @@ -1,128 +1,128 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.library' - - -dependencies { - implementation fileTree(dir: 'libs', include: ['*.jar']) - implementation 'com.android.support:multidex:1.0.3' - implementation(name: 'androidx.activity.activity-1.0.0', ext:'aar') - implementation(name: 'androidx.appcompat.appcompat-1.1.0', ext:'aar') - implementation(name: 'androidx.appcompat.appcompat-resources-1.1.0', ext:'aar') -// implementation(name: 'androidx.browser.browser-1.0.0', ext:'aar') - implementation(name: 'androidx.cardview.cardview-1.0.0', ext:'aar') - implementation(name: 'androidx.core.core-ktx-1.3.2', ext:'aar') - implementation(name: 'androidx.legacy.legacy-support-v4-1.0.0', ext:'aar') - implementation(name: 'androidx.savedstate.savedstate-1.0.0', ext:'aar') - implementation(name: 'androidx.vectordrawable.vectordrawable-animated-1.1.0', ext:'aar') - implementation(name: 'com.android.installreferrer.installreferrer-2.1', ext:'aar') - implementation(name: 'com.appsflyer.af-android-sdk-6.4.1', ext:'aar') - implementation(name: 'com.appsflyer.oaid-6.2.4', ext:'aar') - implementation(name: 'com.appsflyer.unity-wrapper-6.4.1', ext:'aar') - implementation(name: 'com.facebook.android.facebook-applinks-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-common-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-core-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-gamingservices-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-login-11.3.0', ext:'aar') - implementation(name: 'com.facebook.android.facebook-share-11.3.0', ext:'aar') - implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') - implementation(name: 'screenutils-release', ext:'aar') - implementation(name: 'ThinkingSDK', ext:'aar') - implementation(name: 'UnityUtils-release', ext:'aar') - implementation 'com.google.android.gms:play-services-auth:20.1.0' - implementation "com.android.billingclient:billing:5.0.0" - implementation platform('com.google.firebase:firebase-bom:29.2.1') - implementation 'com.google.firebase:firebase-analytics:21.1.0' - implementation 'com.google.firebase:firebase-messaging' - implementation 'com.google.android.gms:play-services-ads:21.0.0' - implementation 'com.google.ads.mediation:facebook:6.11.0.1' - implementation 'com.unity3d.ads:unity-ads:4.2.1' - implementation 'com.google.ads.mediation:unity:4.2.1.1' - implementation 'com.google.ads.mediation:applovin:11.4.4.0' - implementation(name: 'mediationsdk-7.2.3.1', ext:'aar') -} - -android { - compileSdkVersion 30 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_1_8 - targetCompatibility JavaVersion.VERSION_1_8 - } - - defaultConfig { - minSdkVersion 19 - targetSdkVersion 30 - ndk { - abiFilters 'armeabi-v7a' - } - versionCode 1 - versionName '0.1.0' - consumerProguardFiles 'proguard-unity.txt' - } - - lintOptions { - abortOnError false - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - } -} - -def getSdkDir() { - Properties local = new Properties() - local.load(new FileInputStream("${rootDir}/local.properties")) - return local.getProperty('sdk.dir') -} - -def BuildIl2Cpp(String workingDir, String targetDirectory, String architecture, String abi, String configuration) { - exec { - commandLine(workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/netcoreapp3.1/il2cpp", - "--compile-cpp", - "--libil2cpp-static", - "--platform=Android", - "--architecture=" + architecture, - "--configuration=" + configuration, - "--outputpath=" + workingDir + targetDirectory + abi + "/libil2cpp.so", - "--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/external/bdwgc/include", - "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/include", - "--tool-chain-path=" + android.ndkDirectory, - "--map-file-parser=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/MapFileParser/MapFileParser.exe", - "--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput", - "--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi, - "--dotnetprofile=unityaot") - environment "ANDROID_SDK_ROOT", getSdkDir() - } - delete workingDir + targetDirectory + abi + "/libil2cpp.sym.so" - ant.move(file: workingDir + targetDirectory + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") -} - -android { - task BuildIl2CppTask { - doLast { - BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARMv7', 'armeabi-v7a', 'Release'); - } - } - afterEvaluate { - if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) - project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask - if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) - project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask - } - sourceSets { - main { - jni.srcDirs = ["src/main/Il2CppOutputProject"] - } - } -} - - - +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.library' + + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.android.support:multidex:1.0.3' + implementation(name: 'androidx.activity.activity-1.0.0', ext:'aar') + implementation(name: 'androidx.appcompat.appcompat-1.1.0', ext:'aar') + implementation(name: 'androidx.appcompat.appcompat-resources-1.1.0', ext:'aar') +// implementation(name: 'androidx.browser.browser-1.0.0', ext:'aar') + implementation(name: 'androidx.cardview.cardview-1.0.0', ext:'aar') + implementation(name: 'androidx.core.core-ktx-1.3.2', ext:'aar') + implementation(name: 'androidx.legacy.legacy-support-v4-1.0.0', ext:'aar') + implementation(name: 'androidx.savedstate.savedstate-1.0.0', ext:'aar') + implementation(name: 'androidx.vectordrawable.vectordrawable-animated-1.1.0', ext:'aar') + implementation(name: 'com.android.installreferrer.installreferrer-2.1', ext:'aar') + implementation(name: 'com.appsflyer.af-android-sdk-6.4.1', ext:'aar') + implementation(name: 'com.appsflyer.oaid-6.2.4', ext:'aar') + implementation(name: 'com.appsflyer.unity-wrapper-6.4.1', ext:'aar') + implementation(name: 'com.facebook.android.facebook-applinks-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-common-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-core-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-gamingservices-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-login-11.3.0', ext:'aar') + implementation(name: 'com.facebook.android.facebook-share-11.3.0', ext:'aar') + implementation(name: 'facebook-android-wrapper-11.0.0', ext:'aar') + implementation(name: 'screenutils-release', ext:'aar') + implementation(name: 'ThinkingSDK', ext:'aar') + implementation(name: 'UnityUtils-release', ext:'aar') + implementation 'com.google.android.gms:play-services-auth:20.1.0' + implementation "com.android.billingclient:billing:4.0.0" + implementation platform('com.google.firebase:firebase-bom:29.2.1') + implementation 'com.google.firebase:firebase-analytics:21.1.0' + implementation 'com.google.firebase:firebase-messaging' + implementation 'com.google.android.gms:play-services-ads:21.0.0' + implementation 'com.google.ads.mediation:facebook:6.11.0.1' + implementation 'com.unity3d.ads:unity-ads:4.2.1' + implementation 'com.google.ads.mediation:unity:4.2.1.1' + implementation 'com.google.ads.mediation:applovin:11.4.4.0' + implementation(name: 'mediationsdk-7.2.3.1', ext:'aar') +} + +android { + compileSdkVersion 30 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 30 + ndk { + abiFilters 'armeabi-v7a' + } + versionCode 1 + versionName '0.1.0' + consumerProguardFiles 'proguard-unity.txt' + } + + lintOptions { + abortOnError false + } + + aaptOptions { + noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + } +} + +def getSdkDir() { + Properties local = new Properties() + local.load(new FileInputStream("${rootDir}/local.properties")) + return local.getProperty('sdk.dir') +} + +def BuildIl2Cpp(String workingDir, String targetDirectory, String architecture, String abi, String configuration) { + exec { + commandLine(workingDir + "/src/main/Il2CppOutputProject/IL2CPP/build/deploy/netcoreapp3.1/il2cpp", + "--compile-cpp", + "--libil2cpp-static", + "--platform=Android", + "--architecture=" + architecture, + "--configuration=" + configuration, + "--outputpath=" + workingDir + targetDirectory + abi + "/libil2cpp.so", + "--cachedirectory=" + workingDir + "/build/il2cpp_"+ abi + "_" + configuration + "/il2cpp_cache", + "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/external/bdwgc/include", + "--additional-include-directories=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/libil2cpp/include", + "--tool-chain-path=" + android.ndkDirectory, + "--map-file-parser=" + workingDir + "/src/main/Il2CppOutputProject/IL2CPP/MapFileParser/MapFileParser.exe", + "--generatedcppdir=" + workingDir + "/src/main/Il2CppOutputProject/Source/il2cppOutput", + "--baselib-directory=" + workingDir + "/src/main/jniStaticLibs/" + abi, + "--dotnetprofile=unityaot") + environment "ANDROID_SDK_ROOT", getSdkDir() + } + delete workingDir + targetDirectory + abi + "/libil2cpp.sym.so" + ant.move(file: workingDir + targetDirectory + abi + "/libil2cpp.dbg.so", tofile: workingDir + "/symbols/" + abi + "/libil2cpp.so") +} + +android { + task BuildIl2CppTask { + doLast { + BuildIl2Cpp(projectDir.toString().replaceAll('\\\\', '/'), '/src/main/jniLibs/', 'ARMv7', 'armeabi-v7a', 'Release'); + } + } + afterEvaluate { + if (project(':unityLibrary').tasks.findByName('mergeDebugJniLibFolders')) + project(':unityLibrary').mergeDebugJniLibFolders.dependsOn BuildIl2CppTask + if (project(':unityLibrary').tasks.findByName('mergeReleaseJniLibFolders')) + project(':unityLibrary').mergeReleaseJniLibFolders.dependsOn BuildIl2CppTask + } + sourceSets { + main { + jni.srcDirs = ["src/main/Il2CppOutputProject"] + } + } +} + + + diff --git a/BFVersions/android/dz_release/unityLibrary/src/main/AndroidManifest.xml b/BFVersions/android/dz_release/unityLibrary/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 997a26882..92543085c --- a/BFVersions/android/dz_release/unityLibrary/src/main/AndroidManifest.xml +++ b/BFVersions/android/dz_release/unityLibrary/src/main/AndroidManifest.xml @@ -1,54 +1,53 @@ - - - - - - - - - - - - - - - - - - - - - REPLACE_BUILD_ID - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + REPLACE_BUILD_ID + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/BFVersions/android/dz_release/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java b/BFVersions/android/dz_release/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java old mode 100644 new mode 100755 index ca3396058..05e5f71d6 --- a/BFVersions/android/dz_release/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java +++ b/BFVersions/android/dz_release/unityLibrary/src/main/java/com/unity3d/player/UnityPlayerActivity.java @@ -1,188 +1,188 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN -package com.unity3d.player; - -import android.app.Activity; -import android.content.Intent; -import android.content.res.Configuration; -import android.graphics.PixelFormat; -import android.os.Bundle; -import android.view.KeyEvent; -import android.view.MotionEvent; -import android.view.View; -import android.view.Window; -import android.view.WindowManager; -import android.os.Process; -// import android.os.Build; - -// import com.chartboost.sdk.Chartboost; -import com.juzu.dz.third.GooglePlugin; -import com.ironsource.mediationsdk.IronSource; - -public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents -{ - protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code - - // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player - // The command line arguments are passed as a string, separated by spaces - // UnityPlayerActivity calls this from 'onCreate' - // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan - // See https://docs.unity3d.com/Manual/CommandLineArguments.html - // @param cmdLine the current command line arguments, may be null - // @return the modified command line string or null - protected String updateUnityCommandLineArguments(String cmdLine) - { - return cmdLine; - } - - // Setup activity layout - @Override protected void onCreate(Bundle savedInstanceState) - { - requestWindowFeature(Window.FEATURE_NO_TITLE); - super.onCreate(savedInstanceState); - - String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); - getIntent().putExtra("unity", cmdLine); - - mUnityPlayer = new UnityPlayer(this, this); - setContentView(mUnityPlayer); - mUnityPlayer.requestFocus(); - - GooglePlugin.init(this); - } - - // When Unity player unloaded move task to background - @Override public void onUnityPlayerUnloaded() { - moveTaskToBack(true); - } - - // Callback before Unity player process is killed - @Override public void onUnityPlayerQuitted() { - } - - @Override protected void onNewIntent(Intent intent) - { - // To support deep linking, we need to make sure that the client can get access to - // the last sent intent. The clients access this through a JNI api that allows them - // to get the intent set on launch. To update that after launch we have to manually - // replace the intent with the one caught here. - setIntent(intent); - mUnityPlayer.newIntent(intent); - } - - @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { - super.onActivityResult(requestCode, resultCode, data); - GooglePlugin.onActivityResult(requestCode, resultCode, data); - } - - // Quit Unity - @Override protected void onDestroy () - { - GooglePlugin.onDestroy(); - mUnityPlayer.destroy(); - super.onDestroy(); - } - - // If the activity is in multi window mode or resizing the activity is allowed we will use - // onStart/onStop (the visibility callbacks) to determine when to pause/resume. - // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve - // existing behavior. - @Override protected void onStop() - { - super.onStop(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - } - - @Override protected void onStart() - { - super.onStart(); - - if (!MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - } - - // Pause Unity - @Override protected void onPause() - { - super.onPause(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.pause(); - IronSource.onPause(this); - } - - // Resume Unity - @Override protected void onResume() - { - super.onResume(); - - if (MultiWindowSupport.getAllowResizableWindow(this)) - return; - - mUnityPlayer.resume(); - IronSource.onResume(this); - } - - @Override - public void onBackPressed() { - // If an interstitial is on screen, close it. - // if (Chartboost.onBackPressed()) { - // return; - // } else { - // super.onBackPressed(); - // } - } - - // Low Memory Unity - @Override public void onLowMemory() - { - super.onLowMemory(); - mUnityPlayer.lowMemory(); - } - - // Trim Memory Unity - @Override public void onTrimMemory(int level) - { - super.onTrimMemory(level); - if (level == TRIM_MEMORY_RUNNING_CRITICAL) - { - mUnityPlayer.lowMemory(); - } - } - - // This ensures the layout will be correct. - @Override public void onConfigurationChanged(Configuration newConfig) - { - super.onConfigurationChanged(newConfig); - mUnityPlayer.configurationChanged(newConfig); - } - - // Notify Unity of the focus change. - @Override public void onWindowFocusChanged(boolean hasFocus) - { - super.onWindowFocusChanged(hasFocus); - mUnityPlayer.windowFocusChanged(hasFocus); - } - - // For some reason the multiple keyevent type is not supported by the ndk. - // Force event injection by overriding dispatchKeyEvent(). - @Override public boolean dispatchKeyEvent(KeyEvent event) - { - if (event.getAction() == KeyEvent.ACTION_MULTIPLE) - return mUnityPlayer.injectEvent(event); - return super.dispatchKeyEvent(event); - } - - // Pass any events not handled by (unfocused) views straight to UnityPlayer - @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } - @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } - /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN +package com.unity3d.player; + +import android.app.Activity; +import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.PixelFormat; +import android.os.Bundle; +import android.view.KeyEvent; +import android.view.MotionEvent; +import android.view.View; +import android.view.Window; +import android.view.WindowManager; +import android.os.Process; +// import android.os.Build; + +import com.chartboost.sdk.Chartboost; +import com.juzu.dz.third.GooglePlugin; +import com.ironsource.mediationsdk.IronSource; + +public class UnityPlayerActivity extends Activity implements IUnityPlayerLifecycleEvents +{ + protected UnityPlayer mUnityPlayer; // don't change the name of this variable; referenced from native code + + // Override this in your custom UnityPlayerActivity to tweak the command line arguments passed to the Unity Android Player + // The command line arguments are passed as a string, separated by spaces + // UnityPlayerActivity calls this from 'onCreate' + // Supported: -force-gles20, -force-gles30, -force-gles31, -force-gles31aep, -force-gles32, -force-gles, -force-vulkan + // See https://docs.unity3d.com/Manual/CommandLineArguments.html + // @param cmdLine the current command line arguments, may be null + // @return the modified command line string or null + protected String updateUnityCommandLineArguments(String cmdLine) + { + return cmdLine; + } + + // Setup activity layout + @Override protected void onCreate(Bundle savedInstanceState) + { + requestWindowFeature(Window.FEATURE_NO_TITLE); + super.onCreate(savedInstanceState); + + String cmdLine = updateUnityCommandLineArguments(getIntent().getStringExtra("unity")); + getIntent().putExtra("unity", cmdLine); + + mUnityPlayer = new UnityPlayer(this, this); + setContentView(mUnityPlayer); + mUnityPlayer.requestFocus(); + + GooglePlugin.init(this); + } + + // When Unity player unloaded move task to background + @Override public void onUnityPlayerUnloaded() { + moveTaskToBack(true); + } + + // Callback before Unity player process is killed + @Override public void onUnityPlayerQuitted() { + } + + @Override protected void onNewIntent(Intent intent) + { + // To support deep linking, we need to make sure that the client can get access to + // the last sent intent. The clients access this through a JNI api that allows them + // to get the intent set on launch. To update that after launch we have to manually + // replace the intent with the one caught here. + setIntent(intent); + mUnityPlayer.newIntent(intent); + } + + @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { + super.onActivityResult(requestCode, resultCode, data); + GooglePlugin.onActivityResult(requestCode, resultCode, data); + } + + // Quit Unity + @Override protected void onDestroy () + { + GooglePlugin.onDestroy(); + mUnityPlayer.destroy(); + super.onDestroy(); + } + + // If the activity is in multi window mode or resizing the activity is allowed we will use + // onStart/onStop (the visibility callbacks) to determine when to pause/resume. + // Otherwise it will be done in onPause/onResume as Unity has done historically to preserve + // existing behavior. + @Override protected void onStop() + { + super.onStop(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + } + + @Override protected void onStart() + { + super.onStart(); + + if (!MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + } + + // Pause Unity + @Override protected void onPause() + { + super.onPause(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.pause(); + IronSource.onPause(this); + } + + // Resume Unity + @Override protected void onResume() + { + super.onResume(); + + if (MultiWindowSupport.getAllowResizableWindow(this)) + return; + + mUnityPlayer.resume(); + IronSource.onResume(this); + } + + @Override + public void onBackPressed() { + // If an interstitial is on screen, close it. + if (Chartboost.onBackPressed()) { + return; + } else { + super.onBackPressed(); + } + } + + // Low Memory Unity + @Override public void onLowMemory() + { + super.onLowMemory(); + mUnityPlayer.lowMemory(); + } + + // Trim Memory Unity + @Override public void onTrimMemory(int level) + { + super.onTrimMemory(level); + if (level == TRIM_MEMORY_RUNNING_CRITICAL) + { + mUnityPlayer.lowMemory(); + } + } + + // This ensures the layout will be correct. + @Override public void onConfigurationChanged(Configuration newConfig) + { + super.onConfigurationChanged(newConfig); + mUnityPlayer.configurationChanged(newConfig); + } + + // Notify Unity of the focus change. + @Override public void onWindowFocusChanged(boolean hasFocus) + { + super.onWindowFocusChanged(hasFocus); + mUnityPlayer.windowFocusChanged(hasFocus); + } + + // For some reason the multiple keyevent type is not supported by the ndk. + // Force event injection by overriding dispatchKeyEvent(). + @Override public boolean dispatchKeyEvent(KeyEvent event) + { + if (event.getAction() == KeyEvent.ACTION_MULTIPLE) + return mUnityPlayer.injectEvent(event); + return super.dispatchKeyEvent(event); + } + + // Pass any events not handled by (unfocused) views straight to UnityPlayer + @Override public boolean onKeyUp(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onKeyDown(int keyCode, KeyEvent event) { return mUnityPlayer.injectEvent(event); } + @Override public boolean onTouchEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } + /*API12*/ public boolean onGenericMotionEvent(MotionEvent event) { return mUnityPlayer.injectEvent(event); } +} diff --git a/BFVersions/android/dz_release/unityLibrary/src/main/res/xml/network_security_config.xml b/BFVersions/android/dz_release/unityLibrary/src/main/res/xml/network_security_config.xml old mode 100644 new mode 100755 index 3f9b9c92f..0edfdf604 --- a/BFVersions/android/dz_release/unityLibrary/src/main/res/xml/network_security_config.xml +++ b/BFVersions/android/dz_release/unityLibrary/src/main/res/xml/network_security_config.xml @@ -1,9 +1,9 @@ - - - - - - - - - + + + + + + + + + diff --git a/BFVersions/android/google_common/launcher/build.gradle b/BFVersions/android/google_common/launcher/build.gradle old mode 100644 new mode 100755 index 83c42e095..e49d8dd1f --- a/BFVersions/android/google_common/launcher/build.gradle +++ b/BFVersions/android/google_common/launcher/build.gradle @@ -1,72 +1,91 @@ -// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN - -apply plugin: 'com.android.application' -apply plugin: 'com.google.gms.google-services' -apply plugin: 'com.google.firebase.crashlytics' - -dependencies { - implementation project(':unityLibrary') - - } - -android { - compileSdkVersion 34 - buildToolsVersion '30.0.2' - - compileOptions { - sourceCompatibility JavaVersion.VERSION_11 - targetCompatibility JavaVersion.VERSION_11 - } - - defaultConfig { - minSdkVersion 24 - targetSdkVersion 34 - applicationId 'REPLACE_APPLICATION_ID' - ndk { - abiFilters 'armeabi-v7a', 'arm64-v8a' - } - versionCode 1 - versionName '0.1.0' - multiDexEnabled true - } - - aaptOptions { - noCompress = ['.ress', '.resource', '.obb'] + unityStreamingAssets.tokenize(', ') - ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" - } - - lintOptions { - abortOnError false - } - - buildTypes { - debug { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - signingConfig signingConfigs.debug - jniDebuggable true - } - release { - minifyEnabled false - proguardFiles getDefaultProguardFile('proguard-android.txt') - signingConfig signingConfigs.debug - } - } - - packagingOptions { - doNotStrip '*/armeabi-v7a/*.so' - doNotStrip '*/arm64-v8a/*.so' - } - - bundle { - language { - enableSplit = false - } - density { - enableSplit = false - } - abi { - enableSplit = true - } - } -} +// GENERATED BY UNITY. REMOVE THIS COMMENT TO PREVENT OVERWRITING WHEN EXPORTING AGAIN + +apply plugin: 'com.android.application' +apply plugin: 'applovin-quality-service' +apply plugin: 'com.google.gms.google-services' +apply plugin: 'com.google.firebase.crashlytics' + +applovin { + // NOTE: DO NOT CHANGE - this is NOT your AppLovin MAX SDK key - this is a derived key. + apiKey 'c88aa3b89fe7f00054cac82dfdd1621aa02d691dd1d08b9da536e61cccf411fc362937666323b3df646456' +} + +dependencies { + implementation project(':unityLibrary') + + } + +android { + compileSdkVersion 34 + buildToolsVersion '30.0.2' + + compileOptions { + sourceCompatibility JavaVersion.VERSION_11 + targetCompatibility JavaVersion.VERSION_11 + } + + signingConfigs { + release { + storePassword="REPLACE_PASSWORD" + keyPassword="REPLACE_PASSWORD" + keyAlias="juzu" + storeFile=file("../../keystore/dz_keystore.jks") + } + } + + + defaultConfig { + minSdkVersion 24 + targetSdkVersion 34 + applicationId 'REPLACE_APPLICATION_ID' + ndk { + abiFilters 'armeabi-v7a', 'arm64-v8a' + } + versionCode 1 + versionName '0.1.0' + multiDexEnabled true + } + + aaptOptions { + noCompress = ['.unity3d', '.ress', '.resource', '.obb', '.bundle', '.unityexp'] + unityStreamingAssets.tokenize(', ') + ignoreAssetsPattern = "!.svn:!.git:!.ds_store:!*.scc:.*:!CVS:!thumbs.db:!picasa.ini:!*~" + } + + lintOptions { + abortOnError false + } + + buildTypes { + debug { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt') + signingConfig signingConfigs.release + jniDebuggable true + } + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android.txt') + signingConfig signingConfigs.release + } + } + + packagingOptions { + doNotStrip '*/armeabi-v7a/*.so' + doNotStrip '*/arm64-v8a/*.so' + jniLibs { + useLegacyPackaging = true + } + } + + bundle { + language { + enableSplit = false + } + density { + enableSplit = false + } + abi { + enableSplit = true + } + } +} diff --git a/BFVersions/android/google_common/launcher/google-services.json b/BFVersions/android/google_common/launcher/google-services.json old mode 100644 new mode 100755 index fa98ddb06..c8ccc10d3 --- a/BFVersions/android/google_common/launcher/google-services.json +++ b/BFVersions/android/google_common/launcher/google-services.json @@ -1,63 +1,29 @@ -{ - "project_info": { - "project_number": "1008416471093", - "project_id": "knights-combo", - "storage_bucket": "knights-combo.appspot.com" - }, - "client": [ - { - "client_info": { - "mobilesdk_app_id": "1:1008416471093:android:121c54160b7045e499d97c", - "android_client_info": { - "package_name": "com.combo.heroes.puzzle.rpg" - } - }, - "oauth_client": [ - { - "client_id": "1008416471093-e1a8gso0q6mpangmi7lltjilfmqeqp6u.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.combo.heroes.puzzle.rpg", - "certificate_hash": "3d9f0e5ebcb906418204e1a41cd40968a36c71cc" - } - }, - { - "client_id": "1008416471093-eolgs4t98pog1q3oltg4vh726vpggqbd.apps.googleusercontent.com", - "client_type": 1, - "android_info": { - "package_name": "com.combo.heroes.puzzle.rpg", - "certificate_hash": "dd7bea95dbb468b776ad9e979535689371113698" - } - }, - { - "client_id": "1008416471093-e47s7u8a7v31ulr2f7e9j1mdm9llepum.apps.googleusercontent.com", - "client_type": 3 - } - ], - "api_key": [ - { - "current_key": "AIzaSyDtkUzjjkNiAZszdepIDIYss0ioNNbjncA" - } - ], - "services": { - "appinvite_service": { - "other_platform_oauth_client": [ - { - "client_id": "1008416471093-e47s7u8a7v31ulr2f7e9j1mdm9llepum.apps.googleusercontent.com", - "client_type": 3 - }, - { - "client_id": "1008416471093-78jluae6d1tdl8l4qkul3hut7lckd1kc.apps.googleusercontent.com", - "client_type": 2, - "ios_info": { - "bundle_id": "com.combo.heroes.puzzle.rpg", - "app_store_id": "6450101181" - } - } - ] - } - } - } - ], - "configuration_version": "1" +{ + "project_info": { + "project_number": "22951947163", + "project_id": "pull-pull-pull-heroes", + "storage_bucket": "pull-pull-pull-heroes.firebasestorage.app" + }, + "client": [ + { + "client_info": { + "mobilesdk_app_id": "1:22951947163:android:378ebaf483bc3fb9304f3e", + "android_client_info": { + "package_name": "com.fortune.td.game.global" + } + }, + "oauth_client": [], + "api_key": [ + { + "current_key": "AIzaSyAmIdtI6ZwxXfCVILmtZEr9y4CP_e9JpFE" + } + ], + "services": { + "appinvite_service": { + "other_platform_oauth_client": [] + } + } + } + ], + "configuration_version": "1" } \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/AndroidManifest.xml b/BFVersions/android/google_common/launcher/src/main/AndroidManifest.xml old mode 100644 new mode 100755 index 7ce400abb..3095e54c6 --- a/BFVersions/android/google_common/launcher/src/main/AndroidManifest.xml +++ b/BFVersions/android/google_common/launcher/src/main/AndroidManifest.xml @@ -1,7 +1,7 @@ - - - - - - + + + + + + \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/drawable/firebase_icon.png b/BFVersions/android/google_common/launcher/src/main/res/drawable/firebase_icon.png old mode 100644 new mode 100755 index 8b3afdfdf..b874c25a2 Binary files a/BFVersions/android/google_common/launcher/src/main/res/drawable/firebase_icon.png and b/BFVersions/android/google_common/launcher/src/main/res/drawable/firebase_icon.png differ diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-es/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-es/strings.xml old mode 100644 new mode 100755 index 5b58c6eed..e44094536 --- a/BFVersions/android/google_common/launcher/src/main/res/values-es/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-es/strings.xml @@ -1,4 +1,4 @@ - - - Combo de Jinetes + + + Pull Pull Pull Heroes \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-in/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-in/strings.xml old mode 100644 new mode 100755 index 70aead2b3..e44094536 --- a/BFVersions/android/google_common/launcher/src/main/res/values-in/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-in/strings.xml @@ -1,4 +1,4 @@ - - - Ksatria Kombo + + + Pull Pull Pull Heroes \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-ja/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-ja/strings.xml old mode 100644 new mode 100755 index 486a23561..4cea27dae --- a/BFVersions/android/google_common/launcher/src/main/res/values-ja/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-ja/strings.xml @@ -1,4 +1,4 @@ - - - ナイト戦線 + + + プルせよ!ヒーローズ \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-ko/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-ko/strings.xml old mode 100644 new mode 100755 index 79a258916..09b30d308 --- a/BFVersions/android/google_common/launcher/src/main/res/values-ko/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-ko/strings.xml @@ -1,4 +1,4 @@ - - - 워리어 콤보 + + + 픽미픽미 영웅 \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-pt/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-pt/strings.xml old mode 100644 new mode 100755 index 1d1b881c1..e44094536 --- a/BFVersions/android/google_common/launcher/src/main/res/values-pt/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-pt/strings.xml @@ -1,4 +1,4 @@ - - - Cavaleiros do Combo + + + Pull Pull Pull Heroes \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-th/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-th/strings.xml old mode 100644 new mode 100755 index 575ea36cb..e44094536 --- a/BFVersions/android/google_common/launcher/src/main/res/values-th/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-th/strings.xml @@ -1,4 +1,4 @@ - - - อัศวินคอมโบ + + + Pull Pull Pull Heroes \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-v21/styles.xml b/BFVersions/android/google_common/launcher/src/main/res/values-v21/styles.xml old mode 100644 new mode 100755 index fc4509a2a..2630061ba --- a/BFVersions/android/google_common/launcher/src/main/res/values-v21/styles.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-v21/styles.xml @@ -1,5 +1,5 @@ - - - - + + + + diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-v28/styles.xml b/BFVersions/android/google_common/launcher/src/main/res/values-v28/styles.xml old mode 100644 new mode 100755 index aa23d59fb..a17f8019f --- a/BFVersions/android/google_common/launcher/src/main/res/values-v28/styles.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-v28/styles.xml @@ -1,6 +1,6 @@ - - - - + + + + diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-v30/freeformwindow.xml b/BFVersions/android/google_common/launcher/src/main/res/values-v30/freeformwindow.xml old mode 100644 new mode 100755 index 081fb7de7..dcb77289e --- a/BFVersions/android/google_common/launcher/src/main/res/values-v30/freeformwindow.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-v30/freeformwindow.xml @@ -1,8 +1,8 @@ - - - maximize - tablet - phone - landscape - portrait - + + + maximize + tablet + phone + landscape + portrait + diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-vi/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-vi/strings.xml old mode 100644 new mode 100755 index 5c7e4091d..d837403e0 --- a/BFVersions/android/google_common/launcher/src/main/res/values-vi/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-vi/strings.xml @@ -1,4 +1,4 @@ - - - Kỵ Sĩ Liên Hoàn + + + Phiêu Lưu Sinh Tồn - VTC Game \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-zh-rTW/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-zh-rTW/strings.xml old mode 100644 new mode 100755 index a954d4879..04003ca64 --- a/BFVersions/android/google_common/launcher/src/main/res/values-zh-rTW/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-zh-rTW/strings.xml @@ -1,4 +1,4 @@ - - - 賽賽軍團 + + + 抽抽抽英雄 \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values-zh/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values-zh/strings.xml old mode 100644 new mode 100755 index dff77460b..04003ca64 --- a/BFVersions/android/google_common/launcher/src/main/res/values-zh/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values-zh/strings.xml @@ -1,4 +1,4 @@ - - - 赛赛军团 + + + 抽抽抽英雄 \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values/freeformwindow.xml b/BFVersions/android/google_common/launcher/src/main/res/values/freeformwindow.xml old mode 100644 new mode 100755 index 16b407646..48ce31b15 --- a/BFVersions/android/google_common/launcher/src/main/res/values/freeformwindow.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values/freeformwindow.xml @@ -1,8 +1,8 @@ - - - - - - - - + + + + + + + + diff --git a/BFVersions/android/google_common/launcher/src/main/res/values/ids.xml b/BFVersions/android/google_common/launcher/src/main/res/values/ids.xml old mode 100644 new mode 100755 index 2ba560aea..23ba93480 --- a/BFVersions/android/google_common/launcher/src/main/res/values/ids.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values/ids.xml @@ -1,4 +1,4 @@ - - - - + + + + diff --git a/BFVersions/android/google_common/launcher/src/main/res/values/strings.xml b/BFVersions/android/google_common/launcher/src/main/res/values/strings.xml old mode 100644 new mode 100755 index 93570466f..567bcba20 --- a/BFVersions/android/google_common/launcher/src/main/res/values/strings.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values/strings.xml @@ -1,5 +1,5 @@ - - - Knights Combo - Game view + + + Pull Pull Pull Heroes + Game view \ No newline at end of file diff --git a/BFVersions/android/google_common/launcher/src/main/res/values/styles.xml b/BFVersions/android/google_common/launcher/src/main/res/values/styles.xml old mode 100644 new mode 100755 index e334a5f94..01b930720 --- a/BFVersions/android/google_common/launcher/src/main/res/values/styles.xml +++ b/BFVersions/android/google_common/launcher/src/main/res/values/styles.xml @@ -1,12 +1,12 @@ - - - - - - + + + + + + diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java old mode 100644 new mode 100755 index 740236a21..8758ce9b6 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/message/BFMessage.java @@ -1,44 +1,44 @@ -package com.juzu.dz.message; - -/** - * 管理和前端的通信消息以及json字段 - * */ -public class BFMessage { - // Google登录 - public static final int GOOGLE_LOGIN_SUCCESS = 1; - public static final int GOOGLE_LOGIN_FAILED = 2; - // Google登出成功 - public static final int GOOGLE_LOGOUT_SUCCESS = 3; - // Google支付 - public static final int GOOGLE_PAY_SUCCESS = 4; - public static final int GOOGLE_PAY_FAILED = 5; - public static final int GOOGLE_PAY_CANCEL = 6; - public static final int GOOGLE_CONNECT_SUCCESS = 7; - public static final int GOOGLE_CONNECT_FAILED = 8; - public static final int QUERY_PRODUCT_SUCCESS = 9; - public static final int QUERY_PRODUCT_FAILED = 10; - public static final int QUERY_UNCOMPLETE_ORDER_FINISH = 11; - // Google消耗 - public static final int GOOGLE_CONSUME_SUCCESS = 12; - public static final int GOOGLE_CONSUME_FAILED = 13; - // Google登出失败 - public static final int GOOGLE_LOGOUT_FAILED = 14; - // fireBaseToken - public static final int FIREBASE_TOKEN = 15; - // Google订阅 - public static final int QUERY_SUBSCRIBE_FINISH = 16; - // 显示全屏广告成功 - public static final int ADMOB_SHOWED_FULLSCREEN = 17; - // 显示全屏广告失败 - public static final int ADMOB_FAILEDTO_SHOW_FULLSCREEN = 18; - // 拒绝显示全屏广告 - public static final int ADMOB_DISMISSED_FULLSCREEN = 19; - // 加载广告成功 - public static final int ADMOB_LOADED = 20; - // 加载广告失败 - public static final int ADMOB_LOADED_FAILED = 21; - // 获得奖励 - public static final int ADMOB_EARNED_REWARD = 22; - // 初始化状态 - public static final int ADMOB_INITIALIZED = 23; -} +package com.juzu.dz.message; + +/** + * 管理和前端的通信消息以及json字段 + * */ +public class BFMessage { + // Google登录 + public static final int GOOGLE_LOGIN_SUCCESS = 1; + public static final int GOOGLE_LOGIN_FAILED = 2; + // Google登出成功 + public static final int GOOGLE_LOGOUT_SUCCESS = 3; + // Google支付 + public static final int GOOGLE_PAY_SUCCESS = 4; + public static final int GOOGLE_PAY_FAILED = 5; + public static final int GOOGLE_PAY_CANCEL = 6; + public static final int GOOGLE_CONNECT_SUCCESS = 7; + public static final int GOOGLE_CONNECT_FAILED = 8; + public static final int QUERY_PRODUCT_SUCCESS = 9; + public static final int QUERY_PRODUCT_FAILED = 10; + public static final int QUERY_UNCOMPLETE_ORDER_FINISH = 11; + // Google消耗 + public static final int GOOGLE_CONSUME_SUCCESS = 12; + public static final int GOOGLE_CONSUME_FAILED = 13; + // Google登出失败 + public static final int GOOGLE_LOGOUT_FAILED = 14; + // fireBaseToken + public static final int FIREBASE_TOKEN = 15; + // Google订阅 + public static final int QUERY_SUBSCRIBE_FINISH = 16; + // 显示全屏广告成功 + public static final int ADMOB_SHOWED_FULLSCREEN = 17; + // 显示全屏广告失败 + public static final int ADMOB_FAILEDTO_SHOW_FULLSCREEN = 18; + // 拒绝显示全屏广告 + public static final int ADMOB_DISMISSED_FULLSCREEN = 19; + // 加载广告成功 + public static final int ADMOB_LOADED = 20; + // 加载广告失败 + public static final int ADMOB_LOADED_FAILED = 21; + // 获得奖励 + public static final int ADMOB_EARNED_REWARD = 22; + // 初始化状态 + public static final int ADMOB_INITIALIZED = 23; +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/BFFirebaseMessagingService.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/BFFirebaseMessagingService.java old mode 100644 new mode 100755 index dd3f054af..faf20ce07 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/BFFirebaseMessagingService.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/BFFirebaseMessagingService.java @@ -1,50 +1,50 @@ -package com.juzu.dz.third; - -import android.util.Log; -import android.widget.Toast; - -import androidx.annotation.NonNull; -import androidx.core.app.NotificationCompat; - -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.Task; -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.messaging.FirebaseMessagingService; -import com.google.firebase.messaging.RemoteMessage; - -public class BFFirebaseMessagingService extends FirebaseMessagingService { - - /** - * There are two scenarios when onNewToken is called: - * 1) When a new token is generated on initial app startup - * 2) Whenever an existing token is changed - * Under #2, there are three scenarios when the existing token is changed: - * A) App is restored to a new device - * B) User uninstalls/reinstalls the app - * C) User clears app data - */ - - @Override - public void onMessageReceived(RemoteMessage remoteMessage) { - Log.d("TAG", "From: " + remoteMessage.getFrom()); - // Check if message contains a data payload. - if (remoteMessage.getData().size() > 0) { - Log.d("TAG", "Message data payload: " + remoteMessage.getData()); - } - - // Check if message contains a notification payload. - if (remoteMessage.getNotification() != null) { - Log.d("TAG", "Message Notification Body: " + remoteMessage.getNotification().getBody()); - } - } - - @Override - public void onNewToken(String token) { - Log.d("", "Refreshed token: " + token); - sendRegistrationToServer(token); - } - - private void sendRegistrationToServer(String token) { - // TODO: Implement this method to send token to your app server. - } -} +package com.juzu.dz.third; + +import android.util.Log; +import android.widget.Toast; + +import androidx.annotation.NonNull; +import androidx.core.app.NotificationCompat; + +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.messaging.FirebaseMessagingService; +import com.google.firebase.messaging.RemoteMessage; + +public class BFFirebaseMessagingService extends FirebaseMessagingService { + + /** + * There are two scenarios when onNewToken is called: + * 1) When a new token is generated on initial app startup + * 2) Whenever an existing token is changed + * Under #2, there are three scenarios when the existing token is changed: + * A) App is restored to a new device + * B) User uninstalls/reinstalls the app + * C) User clears app data + */ + + @Override + public void onMessageReceived(RemoteMessage remoteMessage) { + Log.d("TAG", "From: " + remoteMessage.getFrom()); + // Check if message contains a data payload. + if (remoteMessage.getData().size() > 0) { + Log.d("TAG", "Message data payload: " + remoteMessage.getData()); + } + + // Check if message contains a notification payload. + if (remoteMessage.getNotification() != null) { + Log.d("TAG", "Message Notification Body: " + remoteMessage.getNotification().getBody()); + } + } + + @Override + public void onNewToken(String token) { + Log.d("", "Refreshed token: " + token); + sendRegistrationToServer(token); + } + + private void sendRegistrationToServer(String token) { + // TODO: Implement this method to send token to your app server. + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleAdmobRewardedVideo.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleAdmobRewardedVideo.java old mode 100644 new mode 100755 index 04abf3bbe..f5012eab6 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleAdmobRewardedVideo.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleAdmobRewardedVideo.java @@ -1,291 +1,302 @@ -// package com.juzu.dz.third; - -// import android.app.Activity; -// import android.content.Intent; -// import android.os.Bundle; -// import android.util.Log; -// import androidx.annotation.NonNull; - -// import com.google.android.gms.ads.AdError; -// import com.google.android.gms.ads.AdRequest; -// import com.google.android.gms.ads.AdValue; -// import com.google.android.gms.ads.AdapterResponseInfo; -// import com.google.android.gms.ads.FullScreenContentCallback; -// import com.google.android.gms.ads.LoadAdError; -// import com.google.android.gms.ads.MobileAds; -// import com.google.android.gms.ads.OnPaidEventListener; -// import com.google.android.gms.ads.OnUserEarnedRewardListener; -// import com.google.android.gms.ads.ResponseInfo; -// import com.google.android.gms.ads.initialization.AdapterStatus; -// import com.google.android.gms.ads.initialization.InitializationStatus; -// import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; -// import com.google.android.gms.ads.rewarded.RewardItem; -// import com.google.android.gms.ads.rewarded.RewardedAd; -// import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; -// import com.juzu.dz.message.BFMessage; - -// import java.util.Map; - -// public class GoogleAdmobRewardedVideo { -// private final String AD_UNIT_ID = "ca-app-pub-1136292565368915/9438857158"; -// private final String LOG_TAG = "RewardedVideo"; -// private static volatile GoogleAdmobRewardedVideo sInstance; -// private RewardedAd rewardedAd; -// private String adPlacement = ""; - -// private boolean isLoading = false; - -// public static GoogleAdmobRewardedVideo getInstance() -// { -// if (sInstance == null) { -// synchronized (GoogleLogin.class) { -// if (sInstance == null) { -// sInstance = new GoogleAdmobRewardedVideo(); -// } -// } -// } -// return sInstance; -// } - -// public void init(Activity activity){ -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "01"); -// GooglePlugin.logEventBundle("admob_sdk_init_start", bundle); -// MobileAds.initialize(activity, new OnInitializationCompleteListener() { -// @Override -// public void onInitializationComplete(InitializationStatus initializationStatus) { -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_INITIALIZED, ""); - -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "02"); -// GooglePlugin.logEventBundle("admob_sdk_init_complete", bundle); -// // loadRewardedAd(activity); -// } -// }); - -// loadRewardedAd(activity); -// } - -// private void pauseGame() { -// } - -// private void resumeGame() { -// } - -// private void loadRewardedAd(Activity activity) { -// if (isLoading) -// { -// return; -// } -// if (rewardedAd == null) { -// isLoading = true; -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "03"); -// bundle.putString("ad_placement", adPlacement); -// GooglePlugin.logEventBundle("admob_ad_request", bundle); -// AdRequest adRequest = new AdRequest.Builder().build(); -// activity.runOnUiThread(new Runnable() { -// public void run() { -// RewardedAd.load( -// activity, -// AD_UNIT_ID, -// adRequest, -// new RewardedAdLoadCallback() { -// @Override -// public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { -// // Handle the error. -// Log.w(LOG_TAG, "loadAdError:" + loadAdError.getMessage()); -// rewardedAd = null; -// isLoading = false; -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_LOADED_FAILED, ""); -// // Toast.makeText(_activity.this, "onAdFailedToLoad", Toast.LENGTH_SHORT).show(); - -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "05"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("error_code", "" + loadAdError.getCode()); -// GooglePlugin.logEventBundle("admob_ad_load_fail", bundle); -// } - -// @Override -// public void onAdLoaded(@NonNull RewardedAd newRewardedAd) { -// Log.w(LOG_TAG, "onAdLoaded"); -// rewardedAd = newRewardedAd; -// isLoading = false; -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_LOADED, ""); - -// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); -// if (responseInfo != null) -// { -// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); -// if (loadedAdapterResponseInfo != null) -// { -// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "04"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("ad_source", adSourceName); -// bundle.putString("ad_response_id", responseInfo.getResponseId()); -// GooglePlugin.logEventBundle("admob_ad_load_success", bundle); -// } -// } - -// // Toast.makeText(_activity.this, "onAdLoaded", Toast.LENGTH_SHORT).show(); -// } -// }); -// } -// }); -// } -// } - -// private void showRewardedVideo(Activity activity) { -// if (rewardedAd == null) { -// Log.w(LOG_TAG, "The rewarded ad wasn't ready yet."); -// return; -// } - -// activity.runOnUiThread(new Runnable() { -// public void run() { -// rewardedAd.setOnPaidEventListener( -// new OnPaidEventListener() { -// @Override -// public void onPaidEvent(@NonNull AdValue adValue) { -// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); -// if (responseInfo != null) -// { -// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); -// if (loadedAdapterResponseInfo != null) -// { -// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "10"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("ad_source", adSourceName); -// bundle.putDouble("ad_value", adValue.getValueMicros()); -// bundle.putString("ad_response_id", responseInfo.getResponseId()); -// GooglePlugin.logEventBundle("admob_ad_open_success", bundle); -// } -// } -// } -// } -// ); -// rewardedAd.setFullScreenContentCallback( -// new FullScreenContentCallback() { -// @Override -// public void onAdShowedFullScreenContent() { -// // Called when ad is shown. -// Log.w(LOG_TAG, "onAdShowedFullScreenContent"); -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_SHOWED_FULLSCREEN, ""); -// } - -// @Override -// public void onAdFailedToShowFullScreenContent(AdError adError) { -// // Called when ad fails to show. -// Log.w(LOG_TAG, "onAdFailedToShowFullScreenContent"); -// // Don't forget to set the ad reference to null so you -// // don't show the ad a second time. - -// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); -// if (responseInfo != null) -// { -// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); -// if (loadedAdapterResponseInfo != null) -// { -// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); - -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "11"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("ad_source", adSourceName); -// bundle.putString("ad_response_id", responseInfo.getResponseId()); -// bundle.putString("error_code", "" + adError.getCode()); -// GooglePlugin.logEventBundle("admob_ad_open_fail", bundle); -// } -// } - -// rewardedAd = null; -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_FAILEDTO_SHOW_FULLSCREEN, ""); -// adPlacement = ""; -// } - -// @Override -// public void onAdDismissedFullScreenContent() { -// // Called when ad is dismissed. -// // Don't forget to set the ad reference to null so you -// // don't show the ad a second time. - -// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); -// if (responseInfo != null) -// { -// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); -// if (loadedAdapterResponseInfo != null) -// { -// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); - -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "12"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("ad_source", adSourceName); -// bundle.putString("ad_response_id", responseInfo.getResponseId()); -// GooglePlugin.logEventBundle("admob_ad_close", bundle); -// } -// } - -// rewardedAd = null; -// Log.w(LOG_TAG, "onAdDismissedFullScreenContent"); -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_DISMISSED_FULLSCREEN, ""); -// } -// }); -// Activity activityContext = activity; -// rewardedAd.show( -// activityContext, -// new OnUserEarnedRewardListener() { -// @Override -// public void onUserEarnedReward(@NonNull RewardItem rewardItem) { -// // Handle the reward. -// Log.w(LOG_TAG, "The user earned the reward."); -// // int rewardAmount = rewardItem.getAmount(); -// // String rewardType = rewardItem.getType(); -// // Log.w(LOG_TAG, "onUserEarnedReward rewardAmount = " + rewardAmount); -// // Log.w(LOG_TAG, "onUserEarnedReward rewardType = " + rewardType); -// // JSONObject json = new JSONObject(); -// // json.put("status", 0); -// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_EARNED_REWARD, ""); - -// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); -// if (responseInfo != null) -// { -// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); -// if (loadedAdapterResponseInfo != null) -// { -// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); - -// Bundle bundle = new Bundle(); -// bundle.putString("flow_seq", "13"); -// bundle.putString("ad_placement", adPlacement); -// bundle.putString("ad_source", adSourceName); -// bundle.putString("ad_response_id", responseInfo.getResponseId()); -// GooglePlugin.logEventBundle("admob_reward_earn", bundle); -// } -// } -// adPlacement = ""; -// } -// }); -// } -// }); -// } - -// public void showFullScreenAds(Activity activity) { -// showRewardedVideo(activity); -// } - -// public void tryLoadRewardedAd(Activity activity) -// { -// loadRewardedAd(activity); -// } - -// public void setAdPlacement(String placement) -// { -// adPlacement = placement; -// } +// package com.juzu.dz.third; + +// import android.app.Activity; +// import android.content.Intent; +// import android.os.Bundle; +// import android.util.Log; +// import androidx.annotation.NonNull; + +// import com.google.android.gms.ads.AdError; +// import com.google.android.gms.ads.AdRequest; +// import com.google.android.gms.ads.AdValue; +// import com.google.android.gms.ads.AdapterResponseInfo; +// import com.google.android.gms.ads.FullScreenContentCallback; +// import com.google.android.gms.ads.LoadAdError; +// import com.google.android.gms.ads.MobileAds; +// import com.google.android.gms.ads.OnPaidEventListener; +// import com.google.android.gms.ads.OnUserEarnedRewardListener; +// import com.google.android.gms.ads.ResponseInfo; +// import com.google.android.gms.ads.initialization.AdapterStatus; +// import com.google.android.gms.ads.initialization.InitializationStatus; +// import com.google.android.gms.ads.initialization.OnInitializationCompleteListener; +// import com.google.android.gms.ads.rewarded.RewardItem; +// import com.google.android.gms.ads.rewarded.RewardedAd; +// import com.google.android.gms.ads.rewarded.RewardedAdLoadCallback; +// import com.juzu.dz.message.BFMessage; + +// import java.util.Map; + +// public class GoogleAdmobRewardedVideo { +// // 这是b2的id,不能直接用 +// // private final String AD_UNIT_ID = "ca-app-pub-1136292565368915/9438857158"; +// private final String AD_UNIT_ID = ""; +// private final String LOG_TAG = "RewardedVideo"; +// private static volatile GoogleAdmobRewardedVideo sInstance; +// private RewardedAd rewardedAd; +// private String adPlacement = ""; + +// boolean isLoading; + +// public static GoogleAdmobRewardedVideo getInstance() +// { +// if (sInstance == null) { +// synchronized (GoogleLogin.class) { +// if (sInstance == null) { +// sInstance = new GoogleAdmobRewardedVideo(); +// } +// } +// } +// return sInstance; +// } + +// public void init(Activity activity){ +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "01"); +// GooglePlugin.logEventBundle("admob_sdk_init_start", bundle); +// MobileAds.initialize(activity, new OnInitializationCompleteListener() { +// @Override +// public void onInitializationComplete(InitializationStatus initializationStatus) { +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_INITIALIZED, ""); + +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "02"); +// GooglePlugin.logEventBundle("admob_sdk_init_complete", bundle); +// // loadRewardedAd(activity); +// } +// }); + +// loadRewardedAd(activity); + +// // startGame(activity); +// } + +// private void pauseGame() { +// } + +// private void resumeGame() { +// } + +// private void loadRewardedAd(Activity activity) { +// if (rewardedAd == null) { +// isLoading = true; +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "03"); +// bundle.putString("ad_placement", adPlacement); +// GooglePlugin.logEventBundle("admob_ad_request", bundle); +// AdRequest adRequest = new AdRequest.Builder().build(); +// activity.runOnUiThread(new Runnable() { +// public void run() { +// RewardedAd.load( +// activity, +// AD_UNIT_ID, +// adRequest, +// new RewardedAdLoadCallback() { +// @Override +// public void onAdFailedToLoad(@NonNull LoadAdError loadAdError) { +// // Handle the error. +// Log.w("RewardedVideo", loadAdError.getMessage()); +// rewardedAd = null; +// isLoading = false; +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_LOADED_FAILED, ""); +// // Toast.makeText(_activity.this, "onAdFailedToLoad", Toast.LENGTH_SHORT).show(); + +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "05"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("error_code", "" + loadAdError.getCode()); +// GooglePlugin.logEventBundle("admob_ad_load_fail", bundle); +// } + +// @Override +// public void onAdLoaded(@NonNull RewardedAd newRewardedAd) { +// Log.w("RewardedVideo", "onAdLoaded"); +// rewardedAd = newRewardedAd; +// isLoading = false; +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_LOADED, ""); + +// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); +// if (responseInfo != null) +// { +// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); +// if (loadedAdapterResponseInfo != null) +// { +// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "04"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("ad_source", adSourceName); +// bundle.putString("ad_response_id", responseInfo.getResponseId()); +// GooglePlugin.logEventBundle("admob_ad_load_success", bundle); +// } +// } + +// // Toast.makeText(_activity.this, "onAdLoaded", Toast.LENGTH_SHORT).show(); +// } +// }); +// } +// }); +// } +// } + +// // private void startGame(Activity activity) { +// // Hide the retry button, load the ad, and start the timer. +// // if (rewardedAd != null && !isLoading) { +// // loadRewardedAd(activity); +// // } +// // createTimer(COUNTER_TIME); +// // gamePaused = false; +// // gameOver = false; +// // } + +// private void showRewardedVideo(Activity activity) { +// if (rewardedAd == null) { +// Log.w("TAG", "The rewarded ad wasn't ready yet."); +// return; +// } + +// activity.runOnUiThread(new Runnable() { +// public void run() { +// rewardedAd.setOnPaidEventListener( +// new OnPaidEventListener() { +// @Override +// public void onPaidEvent(@NonNull AdValue adValue) { +// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); +// if (responseInfo != null) +// { +// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); +// if (loadedAdapterResponseInfo != null) +// { +// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "10"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("ad_source", adSourceName); +// bundle.putDouble("ad_value", adValue.getValueMicros()); +// bundle.putString("ad_response_id", responseInfo.getResponseId()); +// GooglePlugin.logEventBundle("admob_ad_open_success", bundle); +// } +// } +// } +// } +// ); +// rewardedAd.setFullScreenContentCallback( +// new FullScreenContentCallback() { +// @Override +// public void onAdShowedFullScreenContent() { +// // Called when ad is shown. +// Log.w(LOG_TAG, "onAdShowedFullScreenContent"); +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_SHOWED_FULLSCREEN, ""); +// } + +// @Override +// public void onAdFailedToShowFullScreenContent(AdError adError) { +// // Called when ad fails to show. +// Log.w(LOG_TAG, "onAdFailedToShowFullScreenContent"); +// // Don't forget to set the ad reference to null so you +// // don't show the ad a second time. + +// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); +// if (responseInfo != null) +// { +// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); +// if (loadedAdapterResponseInfo != null) +// { +// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); + +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "11"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("ad_source", adSourceName); +// bundle.putString("ad_response_id", responseInfo.getResponseId()); +// bundle.putString("error_code", "" + adError.getCode()); +// GooglePlugin.logEventBundle("admob_ad_open_fail", bundle); +// } +// } + +// rewardedAd = null; +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_FAILEDTO_SHOW_FULLSCREEN, ""); +// adPlacement = ""; +// } + +// @Override +// public void onAdDismissedFullScreenContent() { +// // Called when ad is dismissed. +// // Don't forget to set the ad reference to null so you +// // don't show the ad a second time. + +// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); +// if (responseInfo != null) +// { +// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); +// if (loadedAdapterResponseInfo != null) +// { +// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); + +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "12"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("ad_source", adSourceName); +// bundle.putString("ad_response_id", responseInfo.getResponseId()); +// GooglePlugin.logEventBundle("admob_ad_close", bundle); +// } +// } + +// rewardedAd = null; +// Log.w(LOG_TAG, "onAdDismissedFullScreenContent"); +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_DISMISSED_FULLSCREEN, ""); +// } +// }); +// Activity activityContext = activity; +// rewardedAd.show( +// activityContext, +// new OnUserEarnedRewardListener() { +// @Override +// public void onUserEarnedReward(@NonNull RewardItem rewardItem) { +// // Handle the reward. +// Log.w("TAG", "The user earned the reward."); +// int rewardAmount = rewardItem.getAmount(); +// String rewardType = rewardItem.getType(); +// Log.w(LOG_TAG, "onUserEarnedReward rewardAmount = " + rewardAmount); +// Log.w(LOG_TAG, "onUserEarnedReward rewardType = " + rewardType); +// // JSONObject json = new JSONObject(); +// // json.put("status", 0); +// GooglePlugin.sendMessageToUnity(BFMessage.ADMOB_EARNED_REWARD, ""); + +// ResponseInfo responseInfo = rewardedAd.getResponseInfo(); +// if (responseInfo != null) +// { +// AdapterResponseInfo loadedAdapterResponseInfo = responseInfo.getLoadedAdapterResponseInfo(); +// if (loadedAdapterResponseInfo != null) +// { +// String adSourceName = loadedAdapterResponseInfo.getAdSourceName(); + +// Bundle bundle = new Bundle(); +// bundle.putString("flow_seq", "13"); +// bundle.putString("ad_placement", adPlacement); +// bundle.putString("ad_source", adSourceName); +// bundle.putString("ad_response_id", responseInfo.getResponseId()); +// GooglePlugin.logEventBundle("admob_reward_earn", bundle); +// } +// } +// adPlacement = ""; +// } +// }); +// } +// }); +// } + +// public void showFullScreenAds(Activity activity) { +// Log.w(LOG_TAG, "showFullScreenAds"); +// showRewardedVideo(activity); +// } + +// public void tryLoadRewardedAd(Activity activity) +// { +// loadRewardedAd(activity); +// } + +// public void setAdPlacement(String placement) +// { +// adPlacement = placement; +// } // } \ No newline at end of file diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java old mode 100644 new mode 100755 index 7f31841b3..d0fc1ee99 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleBilling.java @@ -1,459 +1,459 @@ -package com.juzu.dz.third; - -import android.app.Activity; -import android.text.TextUtils; -import android.util.Log; - -import androidx.annotation.NonNull; -import androidx.annotation.Nullable; - -import com.android.billingclient.api.AccountIdentifiers; -import com.android.billingclient.api.AcknowledgePurchaseParams; -import com.android.billingclient.api.AcknowledgePurchaseResponseListener; -import com.android.billingclient.api.BillingClient; -import com.android.billingclient.api.BillingClientStateListener; -import com.android.billingclient.api.BillingFlowParams; -import com.android.billingclient.api.BillingResult; -import com.android.billingclient.api.ConsumeParams; -import com.android.billingclient.api.ConsumeResponseListener; -import com.android.billingclient.api.Purchase; -import com.android.billingclient.api.PurchasesUpdatedListener; -import com.android.billingclient.api.SkuDetails; -import com.android.billingclient.api.SkuDetailsParams; -import com.android.billingclient.api.SkuDetailsResponseListener; -import com.juzu.dz.message.BFMessage; - -import org.json.JSONArray; -import org.json.JSONException; -import org.json.JSONObject; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -public class GoogleBilling { - private static volatile GoogleBilling sInstance; - private static final String LOG_TAG = "GoogleBilling"; - private static BillingClient mGoogleBillingClient; - private Map mPurchase = new HashMap(); - private List mSubList = new ArrayList(); - private List mInAppList = new ArrayList(); - final private static String BASE_64_ENCODED_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq3fn02CUbrnNkF1PYXk1XHuJdJsnUMsUHXaYR83+ZPE2a3NgGHpVsrVakZK28RARQSz8E2x8qy+4bFPji1TTLq+MRY9CAcGzP4HB5eGKhRmsHABJNnfWgMiXxZ/mmW/yQawTY0zmeDX6Z/GSN3SeZo0PmlpM7ZFJpN42vYO6Fs5zgR05SAUDx3uaPwkhZ0Z2bIIhbWaVyxoMy2pDnCfCL5ym1nwdDa8tRMhZ1yWaDdY4KkJ92W0kbyMntjtL9QWFCGcRTGHVEoir4E2nc2bugaOkw0qegng00L65qWnfZ1GFgPW3uNexWsbEc2A5g//bL2/+yDVQWqiJtkdQMKyIKwIDAQAB"; - - public static GoogleBilling getInstance() - { - if (sInstance == null) { - synchronized (GoogleBilling.class) { - if (sInstance == null) { - sInstance = new GoogleBilling(); - } - } - } - return sInstance; - } - - public void init(Activity activity){ - mGoogleBillingClient = BillingClient.newBuilder(activity).setListener(payListener).enablePendingPurchases().build(); - connectGoogleStore(); - } - - public void connectGoogleStore(){ - mGoogleBillingClient.startConnection(new BillingClientStateListener() { - @Override - public void onBillingSetupFinished(BillingResult billingResult) { - if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_SUCCESS, ""); - }else{ - String msg = billingResult.getDebugMessage(); - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); - } - } - - @Override - public void onBillingServiceDisconnected() { - String msg = "disconnected"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); - } - }); - } - - // 查询商品信息,本地化用 - public void queryProductsInfo(String payType, String productInfoJson){ - Log.d(LOG_TAG, "google queryProductsInfo info from unity:" + productInfoJson); - try { - JSONArray array = new JSONArray(productInfoJson); - String[] proList = new String[array.length()]; - for (int i = 0; i < array.length(); i++){ - proList[i] = (String)array.get(i); - } - queryProducts(payType, proList); - } catch (JSONException e) { - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, e.toString()); - } - } - - //通过商品id查询商品详情 - private void queryProducts(String payType, String [] products){ - List pList = Arrays.asList(products); - SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); - params.setSkusList(pList).setType(payType); - mGoogleBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { - @Override - public void onSkuDetailsResponse(BillingResult billingResult, List list) { - if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null){ - Log.d(LOG_TAG, "queryProducts success count:" + list.size()); - if (list.size() == 0){ - String msg = "未查询到商品信息,请检查传入的商品id,或者配置是否生效"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); - return; - } - JSONArray array = new JSONArray(); - List mList = new ArrayList(); - for (SkuDetails skuDetails : list) { - mList.add(skuDetails); - String sku = skuDetails.getSku(); - String price = skuDetails.getPrice();//实际价格 - String originPrice = skuDetails.getOriginalPrice();//原价,如果没折扣,原价=实际价格 - String description = skuDetails.getDescription(); - String originalJson = skuDetails.getOriginalJson(); - String title = skuDetails.getTitle(); - String priceAmountMicros = String.valueOf(skuDetails.getPriceAmountMicros()); - String currencyCode = skuDetails.getPriceCurrencyCode(); - JSONObject info = new JSONObject(); - try { - info.put("sku", sku); - info.put("price", price); - info.put("originPrice", originPrice); - info.put("description", description); - info.put("originalJson", originalJson); - info.put("title", title); - info.put("priceCurrencyCode", currencyCode); - info.put("priceAmountMicros", priceAmountMicros); - } catch (JSONException e) { - e.printStackTrace(); - } - array.put(info); - } - if(payType.equals(BillingClient.SkuType.INAPP)){ - mInAppList = mList; - } - if(payType.equals(BillingClient.SkuType.SUBS)){ - mSubList = mList; - } - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_SUCCESS, array.toString()); - }else{ - String msg = "queryProducts error:" + billingResult.getResponseCode(); - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); - } - } - }); - } - - // 支付 - public void pay(Activity activity, String payType, String productId, String customMsg){ - List skuList = null; - if(payType.equals(BillingClient.SkuType.INAPP)){ - skuList = mInAppList; - } - if(payType.equals(BillingClient.SkuType.SUBS)){ - skuList = mSubList; - } - if (skuList == null || skuList.size() == 0){ - String msg = "no sku"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - return ; - } - SkuDetails paySku = null; - for (SkuDetails details:skuList){ - if (TextUtils.equals(productId, details.getSku())){ - paySku = details; - break; - } - } - if (paySku == null){ - String msg = "sku not found! please contact developer"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - return; - } - // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). - BillingFlowParams flowParams = BillingFlowParams.newBuilder() - .setSkuDetails(paySku) - .setObfuscatedAccountId(customMsg) - .build(); - BillingResult result = mGoogleBillingClient.launchBillingFlow(activity, flowParams); - if (result.getResponseCode() != BillingClient.BillingResponseCode.OK){ - String msg = "Billing failed: + " + result.getDebugMessage(); - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - } - } - - private PurchasesUpdatedListener payListener = new PurchasesUpdatedListener() { - @Override - public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List purchases) { - switch (billingResult.getResponseCode()) { - case BillingClient.BillingResponseCode.OK: - if (null != purchases) { - for (Purchase purchase : purchases) { - handlePurchase(purchase); - } - } else { - String msg = "Null Purchase List Returned from OK response!"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - } - break; - case BillingClient.BillingResponseCode.USER_CANCELED: - Log.i(LOG_TAG, "onPurchasesUpdated: User canceled the purchase"); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_CANCEL, ""); - break; - case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED: - String msg = "onPurchasesUpdated: The user already owns this item"; - Log.i(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - break; - case BillingClient.BillingResponseCode.DEVELOPER_ERROR: - String msg2 = "onPurchasesUpdated: Developer error means that Google Play " + - "does not recognize the configuration. If you are just getting started, " + - "make sure you have configured the application correctly in the " + - "Google Play Console. The SKU product ID must match and the APK you " + - "are using must be signed with release keys."; - - Log.e(LOG_TAG, msg2); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg2); - break; - default: - String msg3 = "BillingResult [" + billingResult.getResponseCode() + "]: " + billingResult.getDebugMessage(); - Log.d(LOG_TAG, msg3); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg3); - } - } - }; - - private void handlePurchase(Purchase purchase) { - if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { - // 支付完成 - if(!purchase.isAcknowledged()){ - mPurchase.put(purchase.getPurchaseToken(),purchase); - } - //验证签名 - String orderId = purchase.getOrderId(); - String originalJson = purchase.getOriginalJson(); - String purchaseToken = purchase.getPurchaseToken(); - ArrayList skus = purchase.getSkus(); - String signature = purchase.getSignature(); - AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); - String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); - boolean succ = verifyValidSignature(originalJson, signature); - JSONObject productInfo = new JSONObject(); - try { - productInfo.put("orderId", orderId); - productInfo.put("purchaseToken", purchaseToken); - productInfo.put("obfuscatedAccountId", obfuscatedAccountId); - productInfo.put("signtureFlag", succ + ""); - if (skus.size() > 0) - { - productInfo.put("productId", skus.get(0)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_SUCCESS, productInfo.toString()); - }else{ - //未付款 - String msg = "purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); - } - } - - //消耗 - public void consumeAsync(String purchaseToken){ - Purchase purchase = mPurchase.get(purchaseToken); - boolean isSub = false; - if(purchase != null){ - if(mSubList != null){ - for(SkuDetails Sku:mSubList){ - for ( String purchaseSku : purchase.getSkus() ) { - if (purchaseSku.equals(Sku.getSku())) { - isSub = true; - break; - } - } - } - } - } - if(isSub){ - handleSubsPurchase(purchase); - }else{ - final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken) - .build(); - mGoogleBillingClient.consumeAsync(consumeParams, (billingResult, purchaseToken1) -> { - if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - Log.d(LOG_TAG, "消耗成功..."); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); - } else { - Log.d(LOG_TAG, "消耗失败..."); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); - } - }); - } - } - - private void handleSubsPurchase(Purchase purchase) { - if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { - if (!purchase.isAcknowledged()) { - AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()) - .build(); - mGoogleBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() { - @Override - public void onAcknowledgePurchaseResponse(BillingResult billingResult) { - if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { - Log.d(LOG_TAG, "订阅成功..."); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); - } else { - Log.d(LOG_TAG, "订阅失败..."); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); - } - } - }); - } - } - } - - //查询缓存的购买交易 - public void queryUncompleteOrder(String payType){ - if (mGoogleBillingClient == null){ - String msg = "queryPurchases billingClient is null"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); - return; - } - mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { - if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { - Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); - } else { - //消耗 - JSONArray jsonArray = new JSONArray(); - for (Purchase purchase : list){ - //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I - if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { - if (!purchase.isAcknowledged()){ - mPurchase.put(purchase.getPurchaseToken(), purchase); - //验证签名 - String orderId = purchase.getOrderId(); - String originalJson = purchase.getOriginalJson(); - String purchaseToken = purchase.getPurchaseToken(); - ArrayList skus = purchase.getSkus(); - String signature = purchase.getSignature(); - AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); - String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); - JSONObject productInfo = new JSONObject(); - try { - productInfo.put("payType", payType); - productInfo.put("orderId", orderId); - productInfo.put("purchaseToken", purchaseToken); - productInfo.put("obfuscatedAccountId", obfuscatedAccountId); - boolean succ = verifyValidSignature(originalJson,signature); - productInfo.put("signtureFlag", String.valueOf(succ)); - productInfo.put("purchaseState", "1"); - if (skus.size() > 0) - { - productInfo.put("productId", skus.get(0)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - jsonArray.put(productInfo); - } - }else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING){ - ArrayList skus = purchase.getSkus(); - JSONObject productInfo = new JSONObject(); - try { - productInfo.put("purchaseState", "2"); - if (skus.size() > 0) - { - productInfo.put("productId", skus.get(0)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - jsonArray.put(productInfo); - } - } - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, jsonArray.toString()); - } - }); - } - - - //查询缓存的訂閲状态 - public void querySubscribeOrder(String payType) { - if (mGoogleBillingClient == null) { - String msg = "queryPurchases billingClient is null"; - Log.d(LOG_TAG, msg); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); - return; - } - mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { - if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { - Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); - } else { - //消耗 - JSONArray jsonArray = new JSONArray(); - for (Purchase purchase : list){ - //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I - if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { - String orderId = purchase.getOrderId(); - String originalJson = purchase.getOriginalJson(); - String purchaseToken = purchase.getPurchaseToken(); - ArrayList skus = purchase.getSkus(); - String signature = purchase.getSignature(); - AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); - String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); - JSONObject productInfo = new JSONObject(); - try { - productInfo.put("payType", payType); - productInfo.put("orderId", orderId); - productInfo.put("purchaseToken", purchaseToken); - productInfo.put("obfuscatedAccountId", obfuscatedAccountId); - boolean succ = verifyValidSignature(originalJson,signature); - productInfo.put("signtureFlag", String.valueOf(succ)); - productInfo.put("purchaseState", "1"); - if (skus.size() > 0) - { - productInfo.put("productId", skus.get(0)); - } - } catch (JSONException e) { - e.printStackTrace(); - } - jsonArray.put(productInfo); - } - } - Log.d(LOG_TAG, "订阅状态查询 " + jsonArray.toString()); - GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, jsonArray.toString()); - } - }); - } - - private boolean verifyValidSignature(String signedData, String signature) { - return Security.verifyPurchase(BASE_64_ENCODED_PUBLIC_KEY, signedData, signature); - } - - public void onDestroy(){ - if (mGoogleBillingClient != null && mGoogleBillingClient.isReady()){ - mGoogleBillingClient.endConnection(); - mGoogleBillingClient = null; - } - } -} +package com.juzu.dz.third; + +import android.app.Activity; +import android.text.TextUtils; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; + +import com.android.billingclient.api.AccountIdentifiers; +import com.android.billingclient.api.AcknowledgePurchaseParams; +import com.android.billingclient.api.AcknowledgePurchaseResponseListener; +import com.android.billingclient.api.BillingClient; +import com.android.billingclient.api.BillingClientStateListener; +import com.android.billingclient.api.BillingFlowParams; +import com.android.billingclient.api.BillingResult; +import com.android.billingclient.api.ConsumeParams; +import com.android.billingclient.api.ConsumeResponseListener; +import com.android.billingclient.api.Purchase; +import com.android.billingclient.api.PurchasesUpdatedListener; +import com.android.billingclient.api.SkuDetails; +import com.android.billingclient.api.SkuDetailsParams; +import com.android.billingclient.api.SkuDetailsResponseListener; +import com.juzu.dz.message.BFMessage; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class GoogleBilling { + private static volatile GoogleBilling sInstance; + private static final String LOG_TAG = "GoogleBilling"; + private static BillingClient mGoogleBillingClient; + private Map mPurchase = new HashMap(); + private List mSubList = new ArrayList(); + private List mInAppList = new ArrayList(); + final private static String BASE_64_ENCODED_PUBLIC_KEY = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtIC/9macCZdKcRamY6XOf+J+ncHwUzrRx18696PPH0kixqIAovJKAISUeZCH28NTBb/t4dwgnPRMjNsviH71BVDOK7ZSm2xkbhi4aQ8lB5afGso9nj0+RaaONQeHMW17sIkqd2DIjiMWlPwt65pdonwXZ4NqQJwNabXMhzHggI9fjHH9mJodqqrKkwwIQtFyDe6OYC9kv6DIHhsVVDTfwKbq5QLJEHnsJKJbhuemI0aN6qwSf8tUxLWRJN+P6g88+tfRo5mI7A+slLdcom8Yf+OSQoXGPQJ6xplrfABTB1V7JymfiZg7JHLql65SwG6zk/GFAD0VcIWTfeogvyElkQIDAQAB"; + + public static GoogleBilling getInstance() + { + if (sInstance == null) { + synchronized (GoogleBilling.class) { + if (sInstance == null) { + sInstance = new GoogleBilling(); + } + } + } + return sInstance; + } + + public void init(Activity activity){ + mGoogleBillingClient = BillingClient.newBuilder(activity).setListener(payListener).enablePendingPurchases().build(); + connectGoogleStore(); + } + + public void connectGoogleStore(){ + mGoogleBillingClient.startConnection(new BillingClientStateListener() { + @Override + public void onBillingSetupFinished(BillingResult billingResult) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_SUCCESS, ""); + }else{ + String msg = billingResult.getDebugMessage(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); + } + } + + @Override + public void onBillingServiceDisconnected() { + String msg = "disconnected"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, msg); + } + }); + } + + // 查询商品信息,本地化用 + public void queryProductsInfo(String payType, String productInfoJson){ + Log.d(LOG_TAG, "google queryProductsInfo info from unity:" + productInfoJson); + try { + JSONArray array = new JSONArray(productInfoJson); + String[] proList = new String[array.length()]; + for (int i = 0; i < array.length(); i++){ + proList[i] = (String)array.get(i); + } + queryProducts(payType, proList); + } catch (JSONException e) { + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, e.toString()); + } + } + + //通过商品id查询商品详情 + private void queryProducts(String payType, String [] products){ + List pList = Arrays.asList(products); + SkuDetailsParams.Builder params = SkuDetailsParams.newBuilder(); + params.setSkusList(pList).setType(payType); + mGoogleBillingClient.querySkuDetailsAsync(params.build(), new SkuDetailsResponseListener() { + @Override + public void onSkuDetailsResponse(BillingResult billingResult, List list) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK && list != null){ + Log.d(LOG_TAG, "queryProducts success count:" + list.size()); + if (list.size() == 0){ + String msg = "未查询到商品信息,请检查传入的商品id,或者配置是否生效"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); + return; + } + JSONArray array = new JSONArray(); + List mList = new ArrayList(); + for (SkuDetails skuDetails : list) { + mList.add(skuDetails); + String sku = skuDetails.getSku(); + String price = skuDetails.getPrice();//实际价格 + String originPrice = skuDetails.getOriginalPrice();//原价,如果没折扣,原价=实际价格 + String description = skuDetails.getDescription(); + String originalJson = skuDetails.getOriginalJson(); + String title = skuDetails.getTitle(); + String priceAmountMicros = String.valueOf(skuDetails.getPriceAmountMicros()); + String currencyCode = skuDetails.getPriceCurrencyCode(); + JSONObject info = new JSONObject(); + try { + info.put("sku", sku); + info.put("price", price); + info.put("originPrice", originPrice); + info.put("description", description); + info.put("originalJson", originalJson); + info.put("title", title); + info.put("priceCurrencyCode", currencyCode); + info.put("priceAmountMicros", priceAmountMicros); + } catch (JSONException e) { + e.printStackTrace(); + } + array.put(info); + } + if(payType.equals(BillingClient.SkuType.INAPP)){ + mInAppList = mList; + } + if(payType.equals(BillingClient.SkuType.SUBS)){ + mSubList = mList; + } + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_SUCCESS, array.toString()); + }else{ + String msg = "queryProducts error:" + billingResult.getResponseCode(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, msg); + } + } + }); + } + + // 支付 + public void pay(Activity activity, String payType, String productId, String customMsg){ + List skuList = null; + if(payType.equals(BillingClient.SkuType.INAPP)){ + skuList = mInAppList; + } + if(payType.equals(BillingClient.SkuType.SUBS)){ + skuList = mSubList; + } + if (skuList == null || skuList.size() == 0){ + String msg = "no sku"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + return ; + } + SkuDetails paySku = null; + for (SkuDetails details:skuList){ + if (TextUtils.equals(productId, details.getSku())){ + paySku = details; + break; + } + } + if (paySku == null){ + String msg = "sku not found! please contact developer"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + return; + } + // Retrieve a value for "skuDetails" by calling querySkuDetailsAsync(). + BillingFlowParams flowParams = BillingFlowParams.newBuilder() + .setSkuDetails(paySku) + .setObfuscatedAccountId(customMsg) + .build(); + BillingResult result = mGoogleBillingClient.launchBillingFlow(activity, flowParams); + if (result.getResponseCode() != BillingClient.BillingResponseCode.OK){ + String msg = "Billing failed: + " + result.getDebugMessage(); + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + } + + private PurchasesUpdatedListener payListener = new PurchasesUpdatedListener() { + @Override + public void onPurchasesUpdated(@NonNull BillingResult billingResult, @Nullable List purchases) { + switch (billingResult.getResponseCode()) { + case BillingClient.BillingResponseCode.OK: + if (null != purchases) { + for (Purchase purchase : purchases) { + handlePurchase(purchase); + } + } else { + String msg = "Null Purchase List Returned from OK response!"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + break; + case BillingClient.BillingResponseCode.USER_CANCELED: + Log.i(LOG_TAG, "onPurchasesUpdated: User canceled the purchase"); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_CANCEL, ""); + break; + case BillingClient.BillingResponseCode.ITEM_ALREADY_OWNED: + String msg = "onPurchasesUpdated: The user already owns this item"; + Log.i(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + break; + case BillingClient.BillingResponseCode.DEVELOPER_ERROR: + String msg2 = "onPurchasesUpdated: Developer error means that Google Play " + + "does not recognize the configuration. If you are just getting started, " + + "make sure you have configured the application correctly in the " + + "Google Play Console. The SKU product ID must match and the APK you " + + "are using must be signed with release keys."; + + Log.e(LOG_TAG, msg2); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg2); + break; + default: + String msg3 = "BillingResult [" + billingResult.getResponseCode() + "]: " + billingResult.getDebugMessage(); + Log.d(LOG_TAG, msg3); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg3); + } + } + }; + + private void handlePurchase(Purchase purchase) { + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + // 支付完成 + if(!purchase.isAcknowledged()){ + mPurchase.put(purchase.getPurchaseToken(),purchase); + } + //验证签名 + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + boolean succ = verifyValidSignature(originalJson, signature); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + productInfo.put("signtureFlag", succ + ""); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_SUCCESS, productInfo.toString()); + }else{ + //未付款 + String msg = "purchase.getPurchaseState() != Purchase.PurchaseState.PURCHASED"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, msg); + } + } + + //消耗 + public void consumeAsync(String purchaseToken){ + Purchase purchase = mPurchase.get(purchaseToken); + boolean isSub = false; + if(purchase != null){ + if(mSubList != null){ + for(SkuDetails Sku:mSubList){ + for ( String purchaseSku : purchase.getSkus() ) { + if (purchaseSku.equals(Sku.getSku())) { + isSub = true; + break; + } + } + } + } + } + if(isSub){ + handleSubsPurchase(purchase); + }else{ + final ConsumeParams consumeParams = ConsumeParams.newBuilder().setPurchaseToken(purchaseToken) + .build(); + mGoogleBillingClient.consumeAsync(consumeParams, (billingResult, purchaseToken1) -> { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "消耗成功..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); + } else { + Log.d(LOG_TAG, "消耗失败..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); + } + }); + } + } + + private void handleSubsPurchase(Purchase purchase) { + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + if (!purchase.isAcknowledged()) { + AcknowledgePurchaseParams acknowledgePurchaseParams = AcknowledgePurchaseParams.newBuilder().setPurchaseToken(purchase.getPurchaseToken()) + .build(); + mGoogleBillingClient.acknowledgePurchase(acknowledgePurchaseParams, new AcknowledgePurchaseResponseListener() { + @Override + public void onAcknowledgePurchaseResponse(BillingResult billingResult) { + if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "订阅成功..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_SUCCESS, ""); + } else { + Log.d(LOG_TAG, "订阅失败..."); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, ""); + } + } + }); + } + } + } + + //查询缓存的购买交易 + public void queryUncompleteOrder(String payType){ + if (mGoogleBillingClient == null){ + String msg = "queryPurchases billingClient is null"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + return; + } + mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { + if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + } else { + //消耗 + JSONArray jsonArray = new JSONArray(); + for (Purchase purchase : list){ + //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + if (!purchase.isAcknowledged()){ + mPurchase.put(purchase.getPurchaseToken(), purchase); + //验证签名 + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("payType", payType); + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + boolean succ = verifyValidSignature(originalJson,signature); + productInfo.put("signtureFlag", String.valueOf(succ)); + productInfo.put("purchaseState", "1"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + }else if (purchase.getPurchaseState() == Purchase.PurchaseState.PENDING){ + ArrayList skus = purchase.getSkus(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("purchaseState", "2"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + } + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, jsonArray.toString()); + } + }); + } + + + //查询缓存的訂閲状态 + public void querySubscribeOrder(String payType) { + if (mGoogleBillingClient == null) { + String msg = "queryPurchases billingClient is null"; + Log.d(LOG_TAG, msg); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + return; + } + mGoogleBillingClient.queryPurchasesAsync(payType, (billingResult, list) -> { + if (billingResult.getResponseCode() != BillingClient.BillingResponseCode.OK) { + Log.d(LOG_TAG, "Billing client was null or result code is:" + billingResult.getDebugMessage()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + } else { + //消耗 + JSONArray jsonArray = new JSONArray(); + for (Purchase purchase : list){ + //商品购买成功,系统还会生成购买令牌,它是一个唯一标识符,表示用户及其所购应用内商品的商品 I + if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED) { + String orderId = purchase.getOrderId(); + String originalJson = purchase.getOriginalJson(); + String purchaseToken = purchase.getPurchaseToken(); + ArrayList skus = purchase.getSkus(); + String signature = purchase.getSignature(); + AccountIdentifiers accountIdentifiers = purchase.getAccountIdentifiers(); + String obfuscatedAccountId = accountIdentifiers.getObfuscatedAccountId(); + JSONObject productInfo = new JSONObject(); + try { + productInfo.put("payType", payType); + productInfo.put("orderId", orderId); + productInfo.put("purchaseToken", purchaseToken); + productInfo.put("obfuscatedAccountId", obfuscatedAccountId); + boolean succ = verifyValidSignature(originalJson,signature); + productInfo.put("signtureFlag", String.valueOf(succ)); + productInfo.put("purchaseState", "1"); + if (skus.size() > 0) + { + productInfo.put("productId", skus.get(0)); + } + } catch (JSONException e) { + e.printStackTrace(); + } + jsonArray.put(productInfo); + } + } + Log.d(LOG_TAG, "订阅状态查询 " + jsonArray.toString()); + GooglePlugin.sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, jsonArray.toString()); + } + }); + } + + private boolean verifyValidSignature(String signedData, String signature) { + return Security.verifyPurchase(BASE_64_ENCODED_PUBLIC_KEY, signedData, signature); + } + + public void onDestroy(){ + if (mGoogleBillingClient != null && mGoogleBillingClient.isReady()){ + mGoogleBillingClient.endConnection(); + mGoogleBillingClient = null; + } + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java old mode 100644 new mode 100755 index 95f5b6fbc..e8ba5da9b --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GoogleLogin.java @@ -1,97 +1,98 @@ -package com.juzu.dz.third; - -import android.app.Activity; -import android.content.Intent; - -import androidx.annotation.NonNull; - -import com.google.android.gms.auth.api.signin.GoogleSignIn; -import com.google.android.gms.auth.api.signin.GoogleSignInAccount; -import com.google.android.gms.auth.api.signin.GoogleSignInClient; -import com.google.android.gms.auth.api.signin.GoogleSignInOptions; -import com.google.android.gms.common.Scopes; -import com.google.android.gms.common.api.ApiException; -import com.google.android.gms.common.api.Scope; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.Task; - -import org.json.JSONException; -import org.json.JSONObject; - -import com.juzu.dz.message.BFMessage; - -public class GoogleLogin { - private static volatile GoogleLogin sInstance; - private GoogleSignInClient mGoogleSignInClient; - private static final int REQUEST_CODE_GOOGLE_SIGN_IN = 1001; /* unique request id */ - private static final String server_client_token = "1008416471093-e47s7u8a7v31ulr2f7e9j1mdm9llepum.apps.googleusercontent.com"; - - public static GoogleLogin getInstance() - { - if (sInstance == null) { - synchronized (GoogleLogin.class) { - if (sInstance == null) { - sInstance = new GoogleLogin(); - } - } - } - return sInstance; - } - - public void init(Activity activity){ - GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) - .requestEmail() - .requestId() - .requestIdToken(server_client_token) - .requestServerAuthCode(server_client_token) - .requestScopes(new Scope(Scopes.PLUS_ME)) - .build(); - mGoogleSignInClient = GoogleSignIn.getClient(activity, gso); - } - - public void login(Activity activity) - { - Intent signInIntent = mGoogleSignInClient.getSignInIntent(); - activity.startActivityForResult(signInIntent, REQUEST_CODE_GOOGLE_SIGN_IN); - } - - public void logout(Activity activity) - { - mGoogleSignInClient.signOut().addOnCompleteListener(activity, new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_SUCCESS, ""); - } - }); - } - - public void onActivityResult(int requestCode, int resultCode, Intent data) - { - if (requestCode == REQUEST_CODE_GOOGLE_SIGN_IN) { - Task task = GoogleSignIn.getSignedInAccountFromIntent(data); - handleSignInResult(task); - } - } - - private void handleSignInResult(Task completedTask) { - try { - GoogleSignInAccount account = completedTask.getResult(ApiException.class); - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_SUCCESS, createLoginInfo(account)); - } catch (ApiException e) { - GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed e:" + e.getStatusCode() + " msg:" + e.getMessage()); - } - } - - private String createLoginInfo(GoogleSignInAccount account){ - String idToken = account.getIdToken(); - String uid = account.getId(); - JSONObject result = new JSONObject(); - try { - result.put("Token", idToken); - result.put("UserId", uid); - } catch (JSONException e) { - e.printStackTrace(); - } - return result.toString(); - } -} +package com.juzu.dz.third; + +import android.app.Activity; +import android.content.Intent; + +import androidx.annotation.NonNull; + +import com.google.android.gms.auth.api.signin.GoogleSignIn; +import com.google.android.gms.auth.api.signin.GoogleSignInAccount; +import com.google.android.gms.auth.api.signin.GoogleSignInClient; +import com.google.android.gms.auth.api.signin.GoogleSignInOptions; +import com.google.android.gms.common.Scopes; +import com.google.android.gms.common.api.ApiException; +import com.google.android.gms.common.api.Scope; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; + +import org.json.JSONException; +import org.json.JSONObject; + +import com.juzu.dz.message.BFMessage; + +public class GoogleLogin { + private static volatile GoogleLogin sInstance; + private GoogleSignInClient mGoogleSignInClient; + private static final int REQUEST_CODE_GOOGLE_SIGN_IN = 1001; /* unique request id */ + private static final String server_client_token = "22951947163-20850c0vsdknh7ts3nai4bs6j85dj5gl.apps.googleusercontent.com"; + + + public static GoogleLogin getInstance() + { + if (sInstance == null) { + synchronized (GoogleLogin.class) { + if (sInstance == null) { + sInstance = new GoogleLogin(); + } + } + } + return sInstance; + } + + public void init(Activity activity){ + GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN) + .requestEmail() + .requestId() + .requestIdToken(server_client_token) + .requestServerAuthCode(server_client_token) + .requestScopes(new Scope(Scopes.PLUS_ME)) + .build(); + mGoogleSignInClient = GoogleSignIn.getClient(activity, gso); + } + + public void login(Activity activity) + { + Intent signInIntent = mGoogleSignInClient.getSignInIntent(); + activity.startActivityForResult(signInIntent, REQUEST_CODE_GOOGLE_SIGN_IN); + } + + public void logout(Activity activity) + { + mGoogleSignInClient.signOut().addOnCompleteListener(activity, new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_SUCCESS, ""); + } + }); + } + + public void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (requestCode == REQUEST_CODE_GOOGLE_SIGN_IN) { + Task task = GoogleSignIn.getSignedInAccountFromIntent(data); + handleSignInResult(task); + } + } + + private void handleSignInResult(Task completedTask) { + try { + GoogleSignInAccount account = completedTask.getResult(ApiException.class); + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_SUCCESS, createLoginInfo(account)); + } catch (ApiException e) { + GooglePlugin.sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed e:" + e.getStatusCode() + " msg:" + e.getMessage()); + } + } + + private String createLoginInfo(GoogleSignInAccount account){ + String idToken = account.getIdToken(); + String uid = account.getId(); + JSONObject result = new JSONObject(); + try { + result.put("Token", idToken); + result.put("UserId", uid); + } catch (JSONException e) { + e.printStackTrace(); + } + return result.toString(); + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java old mode 100644 new mode 100755 index bb0373359..8e86a4353 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/GooglePlugin.java @@ -1,299 +1,499 @@ -package com.juzu.dz.third; - -import android.app.Activity; -import android.content.Intent; -import android.os.Build; -import android.os.Bundle; -import android.util.Log; - -import androidx.annotation.NonNull; -import com.google.android.gms.tasks.OnCompleteListener; -import com.google.android.gms.tasks.Task; -import com.google.firebase.messaging.FirebaseMessaging; -import com.google.firebase.analytics.FirebaseAnalytics; -// import com.google.firebase.crashlytics.FirebaseCrashlytics; -import com.juzu.dz.message.BFMessage; -import com.unity3d.player.UnityPlayer; - -import java.util.Iterator; -import java.util.List; - -import org.json.JSONException; -import org.json.JSONObject; - -public class GooglePlugin { - private static final String LOG_TAG = "GooglePlugin"; - private static GoogleLogin mGoogleLogin = null; - private static GoogleBilling mGoogleBilling = null; - // private static GoogleAdmobRewardedVideo mGoogleAdmobRewardedVideo = null; - private static Activity _activity; - public static FirebaseAnalytics mFirebaseAnalytics; - // private FirebaseCrashlytics mFirebaseCrashlytics; - - public static void init(Activity activity){ - _activity = activity; - mFirebaseAnalytics = FirebaseAnalytics.getInstance(_activity); - } - - public static void initLogin() - { - if (mGoogleLogin == null) - { - mGoogleLogin = GoogleLogin.getInstance(); - mGoogleLogin.init(_activity); - } - } - - public static void initBilling() - { - if (mGoogleBilling == null) - { - mGoogleBilling = GoogleBilling.getInstance(); - mGoogleBilling.init(_activity); - } - } - public static void initAdmobRewardedVideo() - { - Log.d("RewardedVideo", "android initAdmobRewardedVideo"); - // if (mGoogleAdmobRewardedVideo == null) - // { - // mGoogleAdmobRewardedVideo = GoogleAdmobRewardedVideo.getInstance(); - // mGoogleAdmobRewardedVideo.init(_activity); - // } - } - - // 登录 - public static void login() - { - if (mGoogleLogin != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleLogin.login(_activity); - } - }); - }else{ - sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed: not init"); - } - } - - // 登出 - public static void logout() - { - if (mGoogleLogin != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleLogin.logout(_activity); - } - }); - }else{ - sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_FAILED, ""); - } - } - - public static void pay(final String payType, final String productId, final String customMsg) - { - - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.pay(_activity, payType, productId, customMsg); - } - }); - }else{ - sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, "billing not init"); - } - } - - public static void queryProductsInfo(final String payType, final String productJson) - { - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.queryProductsInfo(payType, productJson); - } - }); - }else{ - sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, "billing not init"); - } - } - - public static void consumeAsync(final String purchaseToken) - { - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.consumeAsync(purchaseToken); - } - }); - }else{ - sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, "billing not init"); - } - } - - public static void connectGoogleStore() - { - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.connectGoogleStore(); - } - }); - }else{ - sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, "billing not init"); - } - } - - public static void queryUncompleteOrder(final String payType) - { - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.queryUncompleteOrder(payType); - } - }); - }else{ - sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); - } - } - - public static void querySubscribeOrder(final String payType) - { - if (mGoogleBilling != null){ - UnityPlayer.currentActivity.runOnUiThread(new Runnable() { - @Override - public void run() { - mGoogleBilling.querySubscribeOrder(payType); - } - }); - }else{ - sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); - } - } - - public static void onActivityResult(int requestCode, int resultCode, Intent data) - { - if (mGoogleLogin != null){ - mGoogleLogin.onActivityResult(requestCode, resultCode, data); - } - } - - public static void onDestroy() - { - if (mGoogleBilling != null){ - mGoogleBilling.onDestroy(); - } - } - - public static void getFirebaseToken() - { - FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener() { - @Override - public void onComplete(@NonNull Task task) { - if (!task.isSuccessful()) { - Log.w(LOG_TAG, "Fetching FCM registration token failed", task.getException()); - return; - } - - // Get new FCM registration token - String token = task.getResult(); - GooglePlugin.sendMessageToUnity(BFMessage.FIREBASE_TOKEN, token); - } - }); - } - - public static void tryLoadRewardedAd() - { - Log.w("", "tryLoadRewardedAd"); - // if (mGoogleAdmobRewardedVideo != null) - // { - // mGoogleAdmobRewardedVideo.tryLoadRewardedAd(_activity); - // } - } - - public static void showFullScreenAds() - { - Log.w("", "showFullScreenAds"); - // if (mGoogleAdmobRewardedVideo != null) - // { - // mGoogleAdmobRewardedVideo.showFullScreenAds(_activity); - // } - } - - // log event - public static void logEvent(String eventName, String data) throws JSONException { - Log.w("", "logEvent"); - if (mFirebaseAnalytics == null) { - return; - } - JSONObject properties = new JSONObject(data); - Bundle bundle = new Bundle(); - Iterator iter = properties.keys(); - while (iter.hasNext()) { - String key = (String) iter.next(); - Object value = properties.get(key); - setBundleValue(bundle, key, value); - } - mFirebaseAnalytics.logEvent(eventName, bundle); - } - - public static void logEventBundle(String eventName, Bundle bundle){ - Log.w("", "logEvent"); - if (mFirebaseAnalytics == null) { - return; - } - mFirebaseAnalytics.logEvent(eventName, bundle); - } - - // log crash - public static void logCrash(String key, String stack) { - // this.mFirebaseCrashlytics = FirebaseCrashlytics.getInstance(); - // if (this.mFirebaseCrashlytics == null) - // return; - // this.mFirebaseCrashlytics.setCustomKey(key, stack); - } - - // set bundle to type - private static void setBundleValue(Bundle bundle, String key, Object value) { - if (bundle == null) - return; - - if (value instanceof Double) - bundle.putDouble(key, (Double) value); - else if (value instanceof Float) - bundle.putFloat(key, (Float)value); - else if (value instanceof Integer) - bundle.putInt(key, (Integer)value); - else if (value instanceof Long) - bundle.putLong(key, (Long) value); - else if (value instanceof Boolean) - bundle.putBoolean(key, (Boolean) value); - else - bundle.putString(key, (String) value); - } - - public static void sendMessageToUnity(int code, String msg){ - JSONObject data = new JSONObject(); - try { - data.put("head", code); - data.put("body", msg); - } catch (JSONException e) { - e.printStackTrace(); - } - Log.d(LOG_TAG, code + ":" + msg); - UnityPlayer.UnitySendMessage("SDKManager", "MsgFromAndroidOrIOS", data.toString()); - } - - public static void setAdPlacement(String placement){ - // if (mGoogleAdmobRewardedVideo != null) - // { - // mGoogleAdmobRewardedVideo.setAdPlacement(placement); - // } - } +package com.juzu.dz.third; + +import android.app.Activity; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.PackageInfo; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.Bundle; +import android.preference.PreferenceManager; +import android.util.Log; + +import androidx.annotation.NonNull; +import com.google.android.gms.tasks.OnCompleteListener; +import com.google.android.gms.tasks.Task; +import com.google.android.play.core.review.ReviewInfo; +import com.google.android.play.core.review.ReviewManager; +import com.google.android.play.core.review.ReviewManagerFactory; +import com.google.android.play.core.review.testing.FakeReviewManager; +import com.google.firebase.messaging.FirebaseMessaging; +import com.google.firebase.analytics.FirebaseAnalytics; +import com.google.firebase.crashlytics.FirebaseCrashlytics; +import com.juzu.dz.message.BFMessage; +import com.unity3d.player.UnityPlayer; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.util.EnumMap; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.json.JSONException; +import org.json.JSONObject; + +import static com.google.firebase.crashlytics.internal.Logger.TAG; + +import com.iabtcf.decoder.TCString; + +import com.google.android.ump.ConsentDebugSettings; +import com.google.android.ump.ConsentForm.OnConsentFormDismissedListener; +import com.google.android.ump.ConsentInformation; +import com.google.android.ump.ConsentInformation.PrivacyOptionsRequirementStatus; +import com.google.android.ump.ConsentRequestParameters; +import com.google.android.ump.FormError; +import com.google.android.ump.UserMessagingPlatform; + +public class GooglePlugin { + private static final String LOG_TAG = "GooglePlugin"; + private static GoogleLogin mGoogleLogin = null; + private static GoogleBilling mGoogleBilling = null; + // private static GoogleAdmobRewardedVideo mGoogleAdmobRewardedVideo = null; + private static Activity _activity; + public static FirebaseAnalytics mFirebaseAnalytics; + // private FirebaseCrashlytics mFirebaseCrashlytics; + + private static ConsentInformation consentInformation; + private final AtomicBoolean isMobileAdsInitializeCalled = new AtomicBoolean(false); + + public static void init(Activity activity){ + _activity = activity; + mFirebaseAnalytics = FirebaseAnalytics.getInstance(_activity); + } + + public static void initLogin() + { + if (mGoogleLogin == null) + { + mGoogleLogin = GoogleLogin.getInstance(); + mGoogleLogin.init(_activity); + } + } + + public static void initBilling() + { + if (mGoogleBilling == null) + { + mGoogleBilling = GoogleBilling.getInstance(); + mGoogleBilling.init(_activity); + } + } + public static void initAdmobRewardedVideo() + { + Log.d("RewardedVideo", "android initAdmobRewardedVideo"); + // if (mGoogleAdmobRewardedVideo == null) + // { + // mGoogleAdmobRewardedVideo = GoogleAdmobRewardedVideo.getInstance(); + // mGoogleAdmobRewardedVideo.init(_activity); + // } + } + + public static void initGDPR() + { + initConsentInformation(_activity); + } + + // 登录 + public static void login() + { + if (mGoogleLogin != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleLogin.login(_activity); + } + }); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_LOGIN_FAILED, "google login failed: not init"); + } + } + + // 登出 + public static void logout() + { + if (mGoogleLogin != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleLogin.logout(_activity); + } + }); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_LOGOUT_FAILED, ""); + } + } + + public static void pay(final String payType, final String productId, final String customMsg) + { + + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.pay(_activity, payType, productId, customMsg); + } + }); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_PAY_FAILED, "billing not init"); + } + } + + public static void queryProductsInfo(final String payType, final String productJson) + { + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.queryProductsInfo(payType, productJson); + } + }); + }else{ + sendMessageToUnity(BFMessage.QUERY_PRODUCT_FAILED, "billing not init"); + } + } + + public static void consumeAsync(final String purchaseToken) + { + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.consumeAsync(purchaseToken); + } + }); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_CONSUME_FAILED, "billing not init"); + } + } + + public static void connectGoogleStore() + { + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.connectGoogleStore(); + } + }); + }else{ + sendMessageToUnity(BFMessage.GOOGLE_CONNECT_FAILED, "billing not init"); + } + } + + public static void queryUncompleteOrder(final String payType) + { + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.queryUncompleteOrder(payType); + } + }); + }else{ + sendMessageToUnity(BFMessage.QUERY_UNCOMPLETE_ORDER_FINISH, ""); + } + } + + public static void querySubscribeOrder(final String payType) + { + if (mGoogleBilling != null){ + UnityPlayer.currentActivity.runOnUiThread(new Runnable() { + @Override + public void run() { + mGoogleBilling.querySubscribeOrder(payType); + } + }); + }else{ + sendMessageToUnity(BFMessage.QUERY_SUBSCRIBE_FINISH, ""); + } + } + + public static void onActivityResult(int requestCode, int resultCode, Intent data) + { + if (mGoogleLogin != null){ + mGoogleLogin.onActivityResult(requestCode, resultCode, data); + } + } + + public static void onDestroy() + { + if (mGoogleBilling != null){ + mGoogleBilling.onDestroy(); + } + } + + public static void getFirebaseToken() + { + FirebaseMessaging.getInstance().getToken().addOnCompleteListener(new OnCompleteListener() { + @Override + public void onComplete(@NonNull Task task) { + if (!task.isSuccessful()) { + Log.w(TAG, "Fetching FCM registration token failed", task.getException()); + return; + } + + // Get new FCM registration token + String token = task.getResult(); + GooglePlugin.sendMessageToUnity(BFMessage.FIREBASE_TOKEN, token); + } + }); + } + + public static void tryLoadRewardedAd() + { + Log.w("", "tryLoadRewardedAd"); + // if (mGoogleAdmobRewardedVideo != null) + // { + // mGoogleAdmobRewardedVideo.tryLoadRewardedAd(_activity); + // } + } + + public static void showFullScreenAds() + { + Log.w("", "showFullScreenAds"); + // if (mGoogleAdmobRewardedVideo != null) + // { + // mGoogleAdmobRewardedVideo.showFullScreenAds(_activity); + // } + } + + // log event + public static void logEvent(String eventName, String data) throws JSONException { + Log.w("", "logEvent"); + if (mFirebaseAnalytics == null) { + return; + } + JSONObject properties = new JSONObject(data); + Bundle bundle = new Bundle(); + Iterator iter = properties.keys(); + while (iter.hasNext()) { + String key = (String) iter.next(); + Object value = properties.get(key); + setBundleValue(bundle, key, value); + } + mFirebaseAnalytics.logEvent(eventName, bundle); + } + + public static void logEventBundle(String eventName, Bundle bundle){ + Log.w("", "logEvent"); + if (mFirebaseAnalytics == null) { + return; + } + mFirebaseAnalytics.logEvent(eventName, bundle); + } + + // log crash + public static void logCrash(String key, String stack) { +// this.mFirebaseCrashlytics = FirebaseCrashlytics.getInstance(); +// if (this.mFirebaseCrashlytics == null) +// return; +// this.mFirebaseCrashlytics.setCustomKey(key, stack); + } + + // set bundle to type + private static void setBundleValue(Bundle bundle, String key, Object value) { + if (bundle == null) + return; + + if (value instanceof Double) + bundle.putDouble(key, (Double) value); + else if (value instanceof Float) + bundle.putFloat(key, (Float)value); + else if (value instanceof Integer) + bundle.putInt(key, (Integer)value); + else if (value instanceof Long) + bundle.putLong(key, (Long) value); + else if (value instanceof Boolean) + bundle.putBoolean(key, (Boolean) value); + else + bundle.putString(key, (String) value); + } + + public static void sendMessageToUnity(int code, String msg){ + JSONObject data = new JSONObject(); + try { + data.put("head", code); + data.put("body", msg); + } catch (JSONException e) { + e.printStackTrace(); + } + Log.d(LOG_TAG, code + ":" + msg); + UnityPlayer.UnitySendMessage("SDKManager", "MsgFromAndroidOrIOS", data.toString()); + } + + public static void setAdPlacement(String placement){ + // if (mGoogleAdmobRewardedVideo != null) + // { + // mGoogleAdmobRewardedVideo.setAdPlacement(placement); + // } + } + + private static String getSign(String algorithm) { + try { + PackageInfo info = _activity.getPackageManager().getPackageInfo( + _activity.getPackageName(), PackageManager.GET_SIGNATURES); + byte[] cert = info.signatures[0].toByteArray(); + MessageDigest md = MessageDigest.getInstance(algorithm); + byte[] publicKey = md.digest(cert); + StringBuffer hexString = new StringBuffer(); + for (int i = 0; i < publicKey.length; i++) { + String appendString = Integer.toHexString(0xFF & publicKey[i]) + .toUpperCase(Locale.US); + if (appendString.length() == 1) + hexString.append("0"); + hexString.append(appendString); + hexString.append(":"); + } + String result = hexString.toString(); + return result.substring(0, result.length() - 1); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } catch (NoSuchAlgorithmException e) { + e.printStackTrace(); + } + return ""; + } + + // 初始化GDPR + public static void initConsentInformation(Activity activity) + { + // ConsentDebugSettings debugSettings = new ConsentDebugSettings.Builder(activity) + // .setDebugGeography(ConsentDebugSettings.DebugGeography.DEBUG_GEOGRAPHY_EEA) + // .addTestDeviceHashedId("F760B5027ECC69D34A80D3957A9841A9") // mumu:D77B7887E3BC1B47009579C304F39BE4 vivo:F760B5027ECC69D34A80D3957A9841A9 + // .build(); + + // ConsentRequestParameters params = new ConsentRequestParameters + // .Builder() + // .setConsentDebugSettings(debugSettings) + // .build(); + + ConsentRequestParameters params = new ConsentRequestParameters + .Builder() + .setTagForUnderAgeOfConsent(false) + .build(); + + // Requesting an update to consent information should be called on every app launch. + consentInformation = UserMessagingPlatform.getConsentInformation(activity); + consentInformation.requestConsentInfoUpdate( + activity, + params, + () -> { + UserMessagingPlatform.loadAndShowConsentFormIfRequired( + activity, + loadAndShowError -> { + if (loadAndShowError != null) { + // Consent gathering failed. + Log.w(TAG, String.format("%s: %s", + loadAndShowError.getErrorCode(), + loadAndShowError.getMessage())); + } + // Consent has been gathered. + GooglePlugin.monitorConsentString(); + } + ); + }, + requestConsentError -> { + // Consent gathering failed. + Log.w(TAG, String.format("%s: %s", + requestConsentError.getErrorCode(), + requestConsentError.getMessage())); + }); + + // Check if you can initialize the Google Mobile Ads SDK in parallel + // while checking for new consent information. Consent obtained in + // the previous session can be used to request ads. + + // 不管结果,直接初始化广告 + // init(activity); + } + + public static boolean isPrivacyOptionsRequired() + { + return consentInformation.getPrivacyOptionsRequirementStatus() == PrivacyOptionsRequirementStatus.REQUIRED; + } + + public static void showPrivacyOptionsForm() + { + _activity.runOnUiThread(new Runnable() { + public void run() { + UserMessagingPlatform.showPrivacyOptionsForm( + _activity, + formError -> { + if (formError != null) { + // Handle the error. + } + } + ); + } + }); + } + + public static void resetGDPR() + { + consentInformation.reset(); + } + + // GDPR IAB TCF + public static void monitorConsentString() { + if (mFirebaseAnalytics == null) + return; + SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(UnityPlayer.currentActivity.getApplicationContext()); + if (sharedPrefs == null) + return; + String iabKey = "IABTCF_TCString"; + String tcString = sharedPrefs.getString(iabKey, ""); + if (tcString == "" || tcString.isEmpty()) + return; + // ad_storage + boolean adStorageAllowed = TCString.decode(tcString).getPurposesConsent().contains(1); + // Consent toggle in vendor setting (i.e. Google is not blocked from using consented data at vendor level) + boolean googleConsent = TCString.decode(tcString).getVendorConsent().contains(755); + // Legitimate interest toggle in vendor setting (i.e. Google is not blocked from their legitimate interest) + // boolean googleInterest = TCString.decode(tcString).getVendorLegitimateInterest().contains(755); + // We are checking if consent for ad_storage was given and that Google as vendor has not been excluded from using consented data + FirebaseAnalytics.ConsentStatus consentStatus = adStorageAllowed && googleConsent ? FirebaseAnalytics.ConsentStatus.GRANTED : FirebaseAnalytics.ConsentStatus.DENIED; + // + // Set consent types. + Map consentMap = new EnumMap<>(FirebaseAnalytics.ConsentType.class); + consentMap.put(FirebaseAnalytics.ConsentType.ANALYTICS_STORAGE, consentStatus); + consentMap.put(FirebaseAnalytics.ConsentType.AD_STORAGE, consentStatus); + consentMap.put(FirebaseAnalytics.ConsentType.AD_USER_DATA, consentStatus); + consentMap.put(FirebaseAnalytics.ConsentType.AD_PERSONALIZATION, consentStatus); + mFirebaseAnalytics.setConsent(consentMap); + } + + public static void requestStoreReview() + { + Activity activity = UnityPlayer.currentActivity; + // 未实例Activity + if (activity == null) + { + return; + } + ReviewManager manager = ReviewManagerFactory.create(activity); + // ReviewManager manager = new FakeReviewManager(activity); // 使用FakeReviewManager进行测试 + // 实例 Review Manager 失败 + if (manager == null) + { + return; + } + Task request = manager.requestReviewFlow(); + // 实例Review Request失败 + if (request == null) + { + return; + } + request.addOnCompleteListener(task -> { + if (task.isSuccessful()) { + // We can get the ReviewInfo object + ReviewInfo reviewInfo = task.getResult(); + // launch review + manager.launchReviewFlow(activity, reviewInfo); + } + }); + } + } \ No newline at end of file diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/Security.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/Security.java old mode 100644 new mode 100755 index 8ab8ca595..1dd7fa7d6 --- a/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/Security.java +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/juzu/dz/third/Security.java @@ -1,136 +1,136 @@ -/* - * Copyright (C) 2021 Google Inc. All rights reserved. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.juzu.dz.third; -/* - * This class is an sample of how you can check to make sure your purchases on the device came - * from Google Play. Putting code like this on your server will provide additional protection. - *

- * One thing that you may also wish to consider doing is caching purchase IDs to make replay - * attacks harder. The reason this code isn't just part of the library is to allow - * you to customize it (and rename it!) to make generic patching exploits more difficult. - */ - -import android.text.TextUtils; -import android.util.Base64; -import android.util.Log; - -import java.io.IOException; -import java.security.InvalidKeyException; -import java.security.KeyFactory; -import java.security.NoSuchAlgorithmException; -import java.security.PublicKey; -import java.security.Signature; -import java.security.SignatureException; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.X509EncodedKeySpec; - -/** - * Security-related methods. For a secure implementation, all of this code should be implemented on - * a server that communicates with the application on the device. - */ -class Security { - static final private String TAG = "IABUtil/Security"; - static final private String KEY_FACTORY_ALGORITHM = "RSA"; - static final private String SIGNATURE_ALGORITHM = "SHA1withRSA"; - - /** - * BASE_64_ENCODED_PUBLIC_KEY should be YOUR APPLICATION PUBLIC KEY. You currently get this - * from the Google Play developer console under the "Monetization Setup" category in the - * Licensing area. This build has been setup so that if you define base64EncodedPublicKey in - * your local.properties, it will be echoed into BuildConfig. - */ - - /** - * Verifies that the data was signed with the given signature - * - * @param signedData the signed JSON string (signed, not encrypted) - * @param signature the signature for the data, signed with the private key - */ - static public boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { - if ((TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) - || TextUtils.isEmpty(signature)) - ) { - Log.w(TAG, "Purchase verification failed: missing data."); - return false; - } - try { - PublicKey key = generatePublicKey(base64PublicKey); - return verify(key, signedData, signature); - } catch (IOException e) { - Log.e(TAG, "Error generating PublicKey from encoded key: " + e.getMessage()); - return false; - } - } - - /** - * Generates a PublicKey instance from a string containing the Base64-encoded public key. - * - * @param encodedPublicKey Base64-encoded public key - * @throws IOException if encoding algorithm is not supported or key specification - * is invalid - */ - static private PublicKey generatePublicKey(String encodedPublicKey) throws IOException { - try { - byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT); - KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM); - return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); - } catch (NoSuchAlgorithmException e) { - // "RSA" is guaranteed to be available. - throw new RuntimeException(e); - } catch (InvalidKeySpecException e) { - String msg = "Invalid key specification: " + e; - Log.w(TAG, msg); - throw new IOException(msg); - } - } - - /** - * Verifies that the signature from the server matches the computed signature on the data. - * Returns true if the data is correctly signed. - * - * @param publicKey public key associated with the developer account - * @param signedData signed data from server - * @param signature server signature - * @return true if the data and signature match - */ - static private Boolean verify(PublicKey publicKey, String signedData, String signature) { - byte[] signatureBytes; - try { - signatureBytes = Base64.decode(signature, Base64.DEFAULT); - } catch (IllegalArgumentException e) { - Log.w(TAG, "Base64 decoding failed."); - return false; - } - try { - Signature signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM); - signatureAlgorithm.initVerify(publicKey); - signatureAlgorithm.update(signedData.getBytes()); - if (!signatureAlgorithm.verify(signatureBytes)) { - Log.w(TAG, "Signature verification failed..."); - return false; - } - return true; - } catch (NoSuchAlgorithmException e) { - // "RSA" is guaranteed to be available. - throw new RuntimeException(e); - } catch (InvalidKeyException e) { - Log.e(TAG, "Invalid key specification."); - } catch (SignatureException e) { - Log.e(TAG, "Signature exception."); - } - return false; - } -} +/* + * Copyright (C) 2021 Google Inc. All rights reserved. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.juzu.dz.third; +/* + * This class is an sample of how you can check to make sure your purchases on the device came + * from Google Play. Putting code like this on your server will provide additional protection. + *

+ * One thing that you may also wish to consider doing is caching purchase IDs to make replay + * attacks harder. The reason this code isn't just part of the library is to allow + * you to customize it (and rename it!) to make generic patching exploits more difficult. + */ + +import android.text.TextUtils; +import android.util.Base64; +import android.util.Log; + +import java.io.IOException; +import java.security.InvalidKeyException; +import java.security.KeyFactory; +import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; +import java.security.Signature; +import java.security.SignatureException; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.X509EncodedKeySpec; + +/** + * Security-related methods. For a secure implementation, all of this code should be implemented on + * a server that communicates with the application on the device. + */ +class Security { + static final private String TAG = "IABUtil/Security"; + static final private String KEY_FACTORY_ALGORITHM = "RSA"; + static final private String SIGNATURE_ALGORITHM = "SHA1withRSA"; + + /** + * BASE_64_ENCODED_PUBLIC_KEY should be YOUR APPLICATION PUBLIC KEY. You currently get this + * from the Google Play developer console under the "Monetization Setup" category in the + * Licensing area. This build has been setup so that if you define base64EncodedPublicKey in + * your local.properties, it will be echoed into BuildConfig. + */ + + /** + * Verifies that the data was signed with the given signature + * + * @param signedData the signed JSON string (signed, not encrypted) + * @param signature the signature for the data, signed with the private key + */ + static public boolean verifyPurchase(String base64PublicKey, String signedData, String signature) { + if ((TextUtils.isEmpty(signedData) || TextUtils.isEmpty(base64PublicKey) + || TextUtils.isEmpty(signature)) + ) { + Log.w(TAG, "Purchase verification failed: missing data."); + return false; + } + try { + PublicKey key = generatePublicKey(base64PublicKey); + return verify(key, signedData, signature); + } catch (IOException e) { + Log.e(TAG, "Error generating PublicKey from encoded key: " + e.getMessage()); + return false; + } + } + + /** + * Generates a PublicKey instance from a string containing the Base64-encoded public key. + * + * @param encodedPublicKey Base64-encoded public key + * @throws IOException if encoding algorithm is not supported or key specification + * is invalid + */ + static private PublicKey generatePublicKey(String encodedPublicKey) throws IOException { + try { + byte[] decodedKey = Base64.decode(encodedPublicKey, Base64.DEFAULT); + KeyFactory keyFactory = KeyFactory.getInstance(KEY_FACTORY_ALGORITHM); + return keyFactory.generatePublic(new X509EncodedKeySpec(decodedKey)); + } catch (NoSuchAlgorithmException e) { + // "RSA" is guaranteed to be available. + throw new RuntimeException(e); + } catch (InvalidKeySpecException e) { + String msg = "Invalid key specification: " + e; + Log.w(TAG, msg); + throw new IOException(msg); + } + } + + /** + * Verifies that the signature from the server matches the computed signature on the data. + * Returns true if the data is correctly signed. + * + * @param publicKey public key associated with the developer account + * @param signedData signed data from server + * @param signature server signature + * @return true if the data and signature match + */ + static private Boolean verify(PublicKey publicKey, String signedData, String signature) { + byte[] signatureBytes; + try { + signatureBytes = Base64.decode(signature, Base64.DEFAULT); + } catch (IllegalArgumentException e) { + Log.w(TAG, "Base64 decoding failed."); + return false; + } + try { + Signature signatureAlgorithm = Signature.getInstance(SIGNATURE_ALGORITHM); + signatureAlgorithm.initVerify(publicKey); + signatureAlgorithm.update(signedData.getBytes()); + if (!signatureAlgorithm.verify(signatureBytes)) { + Log.w(TAG, "Signature verification failed..."); + return false; + } + return true; + } catch (NoSuchAlgorithmException e) { + // "RSA" is guaranteed to be available. + throw new RuntimeException(e); + } catch (InvalidKeyException e) { + Log.e(TAG, "Invalid key specification."); + } catch (SignatureException e) { + Log.e(TAG, "Signature exception."); + } + return false; + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationBackgroundThread.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationBackgroundThread.java new file mode 100755 index 000000000..4ad6e4315 --- /dev/null +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationBackgroundThread.java @@ -0,0 +1,187 @@ +package com.unity.androidnotifications; + +import static com.unity.androidnotifications.UnityNotificationManager.KEY_ID; +import static com.unity.androidnotifications.UnityNotificationManager.TAG_UNITY; + +import android.app.Notification; +import android.util.Log; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.LinkedTransferQueue; +import java.util.Enumeration; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +public class UnityNotificationBackgroundThread extends Thread { + private static abstract class Task { + // returns true if notificationIds was modified (needs to be saved) + public abstract boolean run(UnityNotificationManager manager, ConcurrentHashMap notifications); + } + + private static class ScheduleNotificationTask extends Task { + private int notificationId; + private Notification.Builder notificationBuilder; + private boolean isCustomized; + private boolean isNew; + + public ScheduleNotificationTask(int id, Notification.Builder builder, boolean customized, boolean addedNew) { + notificationId = id; + notificationBuilder = builder; + isCustomized = customized; + isNew = addedNew; + } + + @Override + public boolean run(UnityNotificationManager manager, ConcurrentHashMap notifications) { + String id = String.valueOf(notificationId); + Integer ID = Integer.valueOf(notificationId); + boolean didSchedule = false; + try { + UnityNotificationManager.mUnityNotificationManager.performNotificationScheduling(notificationId, notificationBuilder, isCustomized); + didSchedule = true; + } finally { + // if failed to schedule or replace, remove + if (!didSchedule) { + notifications.remove(notificationId); + manager.cancelPendingNotificationIntent(notificationId); + manager.deleteExpiredNotificationIntent(id); + } + } + + return isNew; + } + } + + private static class CancelNotificationTask extends Task { + private int notificationId; + + public CancelNotificationTask(int id) { + notificationId = id; + } + + @Override + public boolean run(UnityNotificationManager manager, ConcurrentHashMap notifications) { + manager.cancelPendingNotificationIntent(notificationId); + if (notifications.remove(notificationId) != null) { + manager.deleteExpiredNotificationIntent(String.valueOf(notificationId)); + return true; + } + + return false; + } + } + + private static class CancelAllNotificationsTask extends Task { + @Override + public boolean run(UnityNotificationManager manager, ConcurrentHashMap notifications) { + if (notifications.isEmpty()) + return false; + + Enumeration ids = notifications.keys(); + while (ids.hasMoreElements()) { + Integer notificationId = ids.nextElement(); + manager.cancelPendingNotificationIntent(notificationId); + manager.deleteExpiredNotificationIntent(String.valueOf(notificationId)); + } + + notifications.clear(); + return true; + } + } + + private static class HousekeepingTask extends Task { + UnityNotificationBackgroundThread thread; + + public HousekeepingTask(UnityNotificationBackgroundThread th) { + thread = th; + } + + @Override + public boolean run(UnityNotificationManager manager, ConcurrentHashMap notifications) { + HashSet notificationIds = new HashSet<>(); + Enumeration ids = notifications.keys(); + while (ids.hasMoreElements()) { + notificationIds.add(String.valueOf(ids.nextElement())); + } + thread.performHousekeeping(notificationIds); + return false; + } + } + + private static final int TASKS_FOR_HOUSEKEEPING = 50; + private LinkedTransferQueue mTasks = new LinkedTransferQueue(); + private ConcurrentHashMap mScheduledNotifications; + private UnityNotificationManager mManager; + private int mTasksSinceHousekeeping = TASKS_FOR_HOUSEKEEPING; // we want hoursekeeping at the start + + public UnityNotificationBackgroundThread(UnityNotificationManager manager, ConcurrentHashMap scheduledNotifications) { + mManager = manager; + mScheduledNotifications = scheduledNotifications; + // rescheduling after reboot may have loaded, otherwise load here + if (mScheduledNotifications.size() == 0) + loadNotifications(); + } + + public void enqueueNotification(int id, Notification.Builder notificationBuilder, boolean customized, boolean addedNew) { + mTasks.add(new UnityNotificationBackgroundThread.ScheduleNotificationTask(id, notificationBuilder, customized, addedNew)); + } + + public void enqueueCancelNotification(int id) { + mTasks.add(new CancelNotificationTask(id)); + } + + public void enqueueCancelAllNotifications() { + mTasks.add(new CancelAllNotificationsTask()); + } + + private void enqueueHousekeeping() { + mTasks.add(new HousekeepingTask(this)); + } + + @Override + public void run() { + boolean haveChanges = false; + while (true) { + try { + Task task = mTasks.take(); + haveChanges |= executeTask(mManager, task, mScheduledNotifications); + if (!(task instanceof HousekeepingTask)) + ++mTasksSinceHousekeeping; + if (mTasks.size() == 0 && haveChanges) { + haveChanges = false; + enqueueHousekeeping(); + } + } catch (InterruptedException e) { + if (mTasks.isEmpty()) + break; + } + } + } + + private boolean executeTask(UnityNotificationManager manager, Task task, ConcurrentHashMap notifications) { + try { + return task.run(manager, notifications); + } catch (Exception e) { + Log.e(TAG_UNITY, "Exception executing notification task", e); + return false; + } + } + + private void performHousekeeping(Set notificationIds) { + // don't do housekeeping if last task we did was housekeeping (other=1) + boolean performHousekeeping = mTasksSinceHousekeeping >= TASKS_FOR_HOUSEKEEPING; + mTasksSinceHousekeeping = 0; + if (performHousekeeping) + mManager.performNotificationHousekeeping(notificationIds); + mManager.saveScheduledNotificationIDs(notificationIds); + } + + private void loadNotifications() { + List notifications = mManager.loadSavedNotifications(); + for (Notification.Builder builder : notifications) { + int id = builder.getExtras().getInt(KEY_ID, -1); + mScheduledNotifications.put(id, builder); + } + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationManager.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationManager.java new file mode 100755 index 000000000..966ca46a1 --- /dev/null +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationManager.java @@ -0,0 +1,1124 @@ +package com.unity.androidnotifications; + +import android.Manifest; +import android.annotation.TargetApi; +import android.app.Activity; +import android.app.ActivityManager; +import android.app.AlarmManager; +import android.app.Notification; +import android.app.NotificationChannel; +import android.app.NotificationChannelGroup; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.content.SharedPreferences; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.drawable.Icon; +import android.net.Uri; +import android.os.AsyncTask; +import android.os.Build; +import android.os.Bundle; +import android.provider.Settings; +import android.service.notification.StatusBarNotification; +import android.util.Log; + +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND; +import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE; +import static android.app.Notification.VISIBILITY_PUBLIC; + +import java.io.InputStream; +import java.lang.Integer; +import java.util.Calendar; +import java.util.Random; +import java.util.Set; +import java.util.HashSet; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.concurrent.ConcurrentHashMap; + +import com.unity3d.player.UnityPlayer; + +public class UnityNotificationManager extends BroadcastReceiver { + static UnityNotificationManager mUnityNotificationManager; + + private Context mContext = null; + private Activity mActivity = null; + private Class mOpenActivity = null; + private UnityNotificationBackgroundThread mBackgroundThread; + private Random mRandom; + private HashSet mVisibleNotifications; + private ConcurrentHashMap mScheduledNotifications; + private NotificationCallback mNotificationCallback; + private int mExactSchedulingSetting = -1; + + private static final int PERMISSION_STATUS_ALLOWED = 1; + private static final int PERMISSION_STATUS_DENIED = 2; + private static final int PERMISSION_STATUS_NOTIFICATIONS_BLOCKED_FOR_APP = 5; + static final String TAG_UNITY = "UnityNotifications"; + + public static final String KEY_FIRE_TIME = "fireTime"; + public static final String KEY_ID = "id"; + public static final String KEY_INTENT_DATA = "data"; + public static final String KEY_LARGE_ICON = "largeIcon"; + public static final String KEY_REPEAT_INTERVAL = "repeatInterval"; + public static final String KEY_NOTIFICATION = "unityNotification"; + public static final String KEY_NOTIFICATION_ID = "com.unity.NotificationID"; + public static final String KEY_SMALL_ICON = "smallIcon"; + public static final String KEY_CHANNEL_ID = "channelID"; + public static final String KEY_SHOW_IN_FOREGROUND = "com.unity.showInForeground"; + public static final String KEY_NOTIFICATION_DISMISSED = "com.unity.NotificationDismissed"; + public static final String KEY_BIG_LARGE_ICON = "com.unity.BigLargeIcon"; + public static final String KEY_BIG_PICTURE = "com.unity.BigPicture"; + public static final String KEY_BIG_CONTENT_TITLE = "com.unity.BigContentTytle"; + public static final String KEY_BIG_SUMMARY_TEXT = "com.unity.BigSummaryText"; + public static final String KEY_BIG_CONTENT_DESCRIPTION = "com.unity.BigContentDescription"; + public static final String KEY_BIG_SHOW_WHEN_COLLAPSED = "com.unity.BigShowWhenCollapsed"; + + static final String NOTIFICATION_CHANNELS_SHARED_PREFS = "UNITY_NOTIFICATIONS"; + static final String NOTIFICATION_CHANNELS_SHARED_PREFS_KEY = "ChannelIDs"; + static final String NOTIFICATION_IDS_SHARED_PREFS = "UNITY_STORED_NOTIFICATION_IDS"; + static final String NOTIFICATION_IDS_SHARED_PREFS_KEY = "UNITY_NOTIFICATION_IDS"; + + private void initialize(Activity activity, NotificationCallback notificationCallback) { + // always assign these, as callback here is always new, activity and context might be + mContext = activity.getApplicationContext(); + mActivity = activity; + mNotificationCallback = notificationCallback; + if (mScheduledNotifications == null) + mScheduledNotifications = new ConcurrentHashMap(); + if (mBackgroundThread == null || !mBackgroundThread.isAlive()) + mBackgroundThread = new UnityNotificationBackgroundThread(this, mScheduledNotifications); + if (mRandom == null) + mRandom = new Random(); + if (mVisibleNotifications == null) + mVisibleNotifications = new HashSet<>(); + + Bundle metaData = getAppMetadata(); + + Boolean rescheduleOnRestart = false; + if (metaData != null) + rescheduleOnRestart = metaData.getBoolean("reschedule_notifications_on_restart", false); + + if (rescheduleOnRestart) { + ComponentName receiver = new ComponentName(mContext, UnityNotificationRestartOnBootReceiver.class); + PackageManager pm = mContext.getPackageManager(); + + pm.setComponentEnabledSetting(receiver, + PackageManager.COMPONENT_ENABLED_STATE_ENABLED, + PackageManager.DONT_KILL_APP); + } + + mOpenActivity = UnityNotificationUtilities.getOpenAppActivity(mContext); + if (mOpenActivity == null) + throw new RuntimeException("Failed to determine Activity to be opened when tapping notification"); + if (!mBackgroundThread.isAlive()) + mBackgroundThread.start(); + } + + static synchronized UnityNotificationManager getNotificationManagerImpl(Context context) { + if (mUnityNotificationManager == null) { + mUnityNotificationManager = new UnityNotificationManager(); + mUnityNotificationManager.mVisibleNotifications = new HashSet<>(); + mUnityNotificationManager.mScheduledNotifications = new ConcurrentHashMap(); + } + + // always assign context, as it might change + mUnityNotificationManager.mContext = context.getApplicationContext(); + return mUnityNotificationManager; + } + + // Called from managed code. + public static synchronized UnityNotificationManager getNotificationManagerImpl(Activity activity, NotificationCallback notificationCallback) { + if (mUnityNotificationManager == null) { + mUnityNotificationManager = new UnityNotificationManager(); + } + + mUnityNotificationManager.initialize(activity, notificationCallback); + return mUnityNotificationManager; + } + + private Bundle getAppMetadata() { + try { + return mContext.getPackageManager().getApplicationInfo(mContext.getPackageName(), PackageManager.GET_META_DATA).metaData; + } catch (PackageManager.NameNotFoundException e) { + return null; + } + } + + public NotificationManager getNotificationManager() { + return (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); + } + + public int getTargetSdk() { + return mContext.getApplicationInfo().targetSdkVersion; + } + + @TargetApi(Build.VERSION_CODES.N) + public int areNotificationsEnabled() { + boolean permissionGranted = true; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) + permissionGranted = mContext.checkCallingOrSelfPermission(Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED; + boolean notificationsEnabled = getNotificationManager().areNotificationsEnabled(); + if (permissionGranted) + return notificationsEnabled ? PERMISSION_STATUS_ALLOWED : PERMISSION_STATUS_NOTIFICATIONS_BLOCKED_FOR_APP; + return PERMISSION_STATUS_DENIED; + } + + public void registerNotificationChannelGroup(String id, String name, String description) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannelGroup group = new NotificationChannelGroup(id, name); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + group.setDescription(description); + } + + getNotificationManager().createNotificationChannelGroup(group); + } + } + + public void deleteNotificationChannelGroup(String id) { + if (id == null) + return; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + getNotificationManager().deleteNotificationChannelGroup(id); + } else { + for (NotificationChannelWrapper c : getNotificationChannels()) { + if (id.equals(c.group)) + deleteNotificationChannel(c.id); + } + } + } + + public void registerNotificationChannel( + String id, + String name, + int importance, + String description, + boolean enableLights, + boolean enableVibration, + boolean canBypassDnd, + boolean canShowBadge, + long[] vibrationPattern, + int lockscreenVisibility, + String group) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel channel = new NotificationChannel(id, name, importance); + channel.setDescription(description); + channel.enableLights(enableLights); + channel.enableVibration(enableVibration); + channel.setBypassDnd(canBypassDnd); + channel.setShowBadge(canShowBadge); + channel.setVibrationPattern(vibrationPattern); + channel.setLockscreenVisibility(lockscreenVisibility); + channel.setGroup(group); + + getNotificationManager().createNotificationChannel(channel); + } else { + SharedPreferences prefs = mContext.getSharedPreferences(NOTIFICATION_CHANNELS_SHARED_PREFS, Context.MODE_PRIVATE); + Set channelIds = new HashSet(prefs.getStringSet(NOTIFICATION_CHANNELS_SHARED_PREFS_KEY, new HashSet())); + channelIds.add(id); // TODO: what if users create the channel again with the same id? + + // Add to notification channel ids SharedPreferences. + SharedPreferences.Editor editor = prefs.edit().clear(); + editor.putStringSet("ChannelIDs", channelIds); + editor.apply(); + + // Store the channel into a SharedPreferences. + SharedPreferences channelPrefs = mContext.getSharedPreferences(getSharedPrefsNameByChannelId(id), Context.MODE_PRIVATE); + editor = channelPrefs.edit(); + + editor.putString("title", name); // Sadly I can't change the "title" here to "name" due to backward compatibility. + editor.putInt("importance", importance); + editor.putString("description", description); + editor.putBoolean("enableLights", enableLights); + editor.putBoolean("enableVibration", enableVibration); + editor.putBoolean("canBypassDnd", canBypassDnd); + editor.putBoolean("canShowBadge", canShowBadge); + editor.putString("vibrationPattern", Arrays.toString(vibrationPattern)); + editor.putInt("lockscreenVisibility", lockscreenVisibility); + editor.putString("group", group); + + editor.apply(); + } + } + + private static String getSharedPrefsNameByChannelId(String id) + { + return String.format("unity_notification_channel_%s", id); + } + + public NotificationChannelWrapper getNotificationChannel(String id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + NotificationChannel ch = getNotificationManagerImpl(mContext).getNotificationManager().getNotificationChannel(id); + if (ch == null) + return null; + return notificationChannelToWrapper(ch); + } + + SharedPreferences prefs = mContext.getSharedPreferences(getSharedPrefsNameByChannelId(id), Context.MODE_PRIVATE); + NotificationChannelWrapper channel = new NotificationChannelWrapper(); + + channel.id = id; + channel.name = prefs.getString("title", "undefined"); + channel.importance = prefs.getInt("importance", NotificationManager.IMPORTANCE_DEFAULT); + channel.description = prefs.getString("description", "undefined"); + channel.enableLights = prefs.getBoolean("enableLights", false); + channel.enableVibration = prefs.getBoolean("enableVibration", false); + channel.canBypassDnd = prefs.getBoolean("canBypassDnd", false); + channel.canShowBadge = prefs.getBoolean("canShowBadge", false); + channel.lockscreenVisibility = prefs.getInt("lockscreenVisibility", VISIBILITY_PUBLIC); + channel.group = prefs.getString("group", null); + String[] vibrationPatternStr = prefs.getString("vibrationPattern", "[]").split(","); + + long[] vibrationPattern = new long[vibrationPatternStr.length]; + + if (vibrationPattern.length > 1) { + for (int i = 0; i < vibrationPatternStr.length; i++) { + try { + vibrationPattern[i] = Long.parseLong(vibrationPatternStr[i]); + } catch (NumberFormatException e) { + vibrationPattern[i] = 1; + } + } + } + + channel.vibrationPattern = vibrationPattern.length > 1 ? vibrationPattern : null; + return channel; + } + + @TargetApi(Build.VERSION_CODES.O) + private static NotificationChannelWrapper notificationChannelToWrapper(Object chan) { + // Possibly unavailable classes cannot be in API, breaks reflection code looping over when searching for method + NotificationChannel channel = (NotificationChannel)chan; + NotificationChannelWrapper wrapper = new NotificationChannelWrapper(); + + wrapper.id = channel.getId(); + wrapper.name = channel.getName().toString(); + wrapper.importance = channel.getImportance(); + wrapper.description = channel.getDescription(); + wrapper.enableLights = channel.shouldShowLights(); + wrapper.enableVibration = channel.shouldVibrate(); + wrapper.canBypassDnd = channel.canBypassDnd(); + wrapper.canShowBadge = channel.canShowBadge(); + wrapper.vibrationPattern = channel.getVibrationPattern(); + wrapper.lockscreenVisibility = channel.getLockscreenVisibility(); + wrapper.group = channel.getGroup(); + + return wrapper; + } + + public void deleteNotificationChannel(String id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + getNotificationManager().deleteNotificationChannel(id); + } else { + SharedPreferences prefs = mContext.getSharedPreferences(NOTIFICATION_CHANNELS_SHARED_PREFS, Context.MODE_PRIVATE); + Set channelIds = prefs.getStringSet(NOTIFICATION_CHANNELS_SHARED_PREFS_KEY, new HashSet()); + + if (!channelIds.contains(id)) + return; + + // Remove from the notification channel ids SharedPreferences. + channelIds = new HashSet(channelIds); + channelIds.remove(id); + SharedPreferences.Editor editor = prefs.edit().clear(); + editor.putStringSet(NOTIFICATION_CHANNELS_SHARED_PREFS_KEY, channelIds); + editor.apply(); + + // Delete the notification channel SharedPreferences. + SharedPreferences channelPrefs = mContext.getSharedPreferences(getSharedPrefsNameByChannelId(id), Context.MODE_PRIVATE); + channelPrefs.edit().clear().apply(); + } + } + + public NotificationChannelWrapper[] getNotificationChannels() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + List channels = getNotificationManager().getNotificationChannels(); + if (channels.size() == 0) + return null; + NotificationChannelWrapper[] channelList = new NotificationChannelWrapper[channels.size()]; + int i = 0; + for (NotificationChannel ch : channels) { + channelList[i++] = notificationChannelToWrapper(ch); + } + + return channelList; + } else { + SharedPreferences prefs = mContext.getSharedPreferences(NOTIFICATION_CHANNELS_SHARED_PREFS, Context.MODE_PRIVATE); + Set channelIdsSet = prefs.getStringSet(NOTIFICATION_CHANNELS_SHARED_PREFS_KEY, new HashSet()); + if (channelIdsSet.size() == 0) + return null; + NotificationChannelWrapper[] channels = new NotificationChannelWrapper[channelIdsSet.size()]; + int i = 0; + for (String k : channelIdsSet) { + channels[i++] = getNotificationChannel(k); + } + return channels; + } + } + + private int generateUniqueId() { + int id = 0; + do { + id += mRandom.nextInt(1000); + } while (mScheduledNotifications.containsKey(Integer.valueOf(id))); + + return id; + } + + public int scheduleNotification(Notification.Builder notificationBuilder, boolean customized) { + Bundle extras = notificationBuilder.getExtras(); + int id; + if (extras.containsKey(KEY_ID)) + id = notificationBuilder.getExtras().getInt(KEY_ID, -1); + else { + id = generateUniqueId(); + extras.putInt(KEY_ID, id); + } + + boolean addedNew = mScheduledNotifications.putIfAbsent(id, notificationBuilder) == null; + mBackgroundThread.enqueueNotification(id, notificationBuilder, customized, addedNew); + return id; + } + + void performNotificationScheduling(int id, Notification.Builder notificationBuilder, boolean customized) { + Bundle extras = notificationBuilder.getExtras(); + long repeatInterval = extras.getLong(KEY_REPEAT_INTERVAL, -1); + long fireTime = extras.getLong(KEY_FIRE_TIME, -1); + + // if less than a second in the future, notify right away + boolean fireNow = fireTime - Calendar.getInstance().getTime().getTime() < 1000; + if (!fireNow || repeatInterval > 0) { + if (fireNow) { + // schedule at next repetition + fireTime += repeatInterval; + } + + Intent intent = buildNotificationIntent(); + + if (intent != null) { + saveNotification(notificationBuilder.build(), customized); + scheduleAlarmWithNotification(notificationBuilder, intent, fireTime); + } + } + + if (fireNow) { + Notification notification = buildNotificationForSending(mOpenActivity, notificationBuilder); + notify(id, notification); + } + } + + void scheduleAlarmWithNotification(Notification.Builder notificationBuilder, Intent intent, long fireTime) { + Bundle extras = notificationBuilder.getExtras(); + int id = extras.getInt(KEY_ID, -1); + long repeatInterval = extras.getLong(KEY_REPEAT_INTERVAL, -1); + // fireTime not taken from notification, because we may have adjusted it + + // when rescheduling after boot notification may be absent + // also, we may be replacing an existing notification + mScheduledNotifications.put(Integer.valueOf(id), notificationBuilder); + intent.putExtra(KEY_NOTIFICATION_ID, id); + + PendingIntent broadcast = getBroadcastPendingIntent(id, intent, PendingIntent.FLAG_UPDATE_CURRENT); + scheduleNotificationIntentAlarm(repeatInterval, fireTime, broadcast); + } + + void scheduleAlarmWithNotification(Notification.Builder notificationBuilder) { + long fireTime = notificationBuilder.getExtras().getLong(KEY_FIRE_TIME, 0L); + Intent intent = buildNotificationIntent(); + scheduleAlarmWithNotification(notificationBuilder, intent, fireTime); + } + + private Notification buildNotificationForSending(Class openActivity, Notification.Builder builder) { + int id = builder.getExtras().getInt(KEY_ID, -1); + Intent openAppIntent = new Intent(mContext, openActivity); + openAppIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP); + openAppIntent.putExtra(KEY_NOTIFICATION_ID, id); + PendingIntent pendingIntent = getActivityPendingIntent(id, openAppIntent, 0); + builder.setContentIntent(pendingIntent); + + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + // Can't check StatusBar notifications pre-M, so ask to be notified when dismissed + Intent deleteIntent = new Intent(mContext, UnityNotificationManager.class); + deleteIntent.setAction(KEY_NOTIFICATION_DISMISSED); // need action to distinguish intent from content one + deleteIntent.putExtra(KEY_NOTIFICATION_DISMISSED, id); + PendingIntent deletePending = getBroadcastPendingIntent(id, deleteIntent, 0); + builder.setDeleteIntent(deletePending); + } + + finalizeNotificationForDisplay(builder); + return builder.build(); + } + + void performNotificationHousekeeping(Set ids) { + Log.d(TAG_UNITY, "Checking for invalid notification IDs still hanging around"); + + Set invalid = findInvalidNotificationIds(ids); + Set currentIds = new HashSet<>(ids); + for (String id : invalid) { + currentIds.remove(id); + mScheduledNotifications.remove(id); + } + + // in case we have saved intents, clear them + for (String id : invalid) + deleteExpiredNotificationIntent(id); + } + + private Set findInvalidNotificationIds(Set ids) { + Intent intent = buildNotificationIntent(); + HashSet invalid = new HashSet(); + for (String id : ids) { + // Get the given broadcast PendingIntent by id as request code. + // FLAG_NO_CREATE is set to return null if the described PendingIntent doesn't exist. + PendingIntent broadcast = getBroadcastPendingIntent(Integer.valueOf(id), intent, PendingIntent.FLAG_NO_CREATE); + if (broadcast == null) { + invalid.add(id); + } + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + StatusBarNotification[] active = getNotificationManager().getActiveNotifications(); + for (StatusBarNotification notification : active) { + // any notifications in status bar are still valid + String id = String.valueOf(notification.getId()); + invalid.remove(id); + } + } + else synchronized (this) { + for (Integer visibleId : mVisibleNotifications) { + String id = String.valueOf(visibleId); + invalid.remove(id); + } + } + + // if app is launched with notification, user still has access to it + if (UnityPlayer.currentActivity != null) { + Intent currentIntent = UnityPlayer.currentActivity.getIntent(); + if (currentIntent.hasExtra(KEY_NOTIFICATION_ID)) { + int id = currentIntent.getExtras().getInt(KEY_NOTIFICATION_ID); + invalid.remove(String.valueOf(id)); + } + } + + return invalid; + } + + private Intent buildNotificationIntent() { + Intent intent = new Intent(mContext, UnityNotificationManager.class); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + return intent; + } + + private PendingIntent getActivityPendingIntent(int id, Intent intent, int flags) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + return PendingIntent.getActivity(mContext, id, intent, flags | PendingIntent.FLAG_IMMUTABLE); + else + return PendingIntent.getActivity(mContext, id, intent, flags); + } + + private PendingIntent getBroadcastPendingIntent(int id, Intent intent, int flags) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + return PendingIntent.getBroadcast(mContext, id, intent, flags | PendingIntent.FLAG_IMMUTABLE); + else + return PendingIntent.getBroadcast(mContext, id, intent, flags); + } + + // Save the notification intent to SharedPreferences if reschedule_on_restart is true, + // which will be consumed by UnityNotificationRestartOnBootReceiver for device reboot. + synchronized void saveNotification(Notification notification, boolean customized) { + String notification_id = Integer.toString(notification.extras.getInt(KEY_ID, -1)); + SharedPreferences prefs = mContext.getSharedPreferences(getSharedPrefsNameByNotificationId(notification_id), Context.MODE_PRIVATE); + UnityNotificationUtilities.serializeNotification(prefs, notification, customized); + } + + static String getSharedPrefsNameByNotificationId(String id) { + return String.format("u_notification_data_%s", id); + } + + // Load all the notification intents from SharedPreferences. + synchronized List loadSavedNotifications() { + Set ids = getScheduledNotificationIDs(); + + List intent_data_list = new ArrayList(); + Set idsMarkedForRemoval = new HashSet(); + + for (String id : ids) { + SharedPreferences prefs = mContext.getSharedPreferences(getSharedPrefsNameByNotificationId(id), Context.MODE_PRIVATE); + Notification.Builder builder = null; + Object notification = UnityNotificationUtilities.deserializeNotification(mContext, prefs); + if (notification != null) { + if (notification instanceof Notification.Builder) + builder = (Notification.Builder)notification; + else + builder = UnityNotificationUtilities.recoverBuilder(mContext, (Notification)notification); + } + + if (builder != null) + intent_data_list.add(builder); + else + idsMarkedForRemoval.add(id); + } + + if (idsMarkedForRemoval.size() > 0) { + ids = new HashSet<>(ids); + for (String id : idsMarkedForRemoval) { + ids.remove(id); + deleteExpiredNotificationIntent(id); + } + saveScheduledNotificationIDs(ids); + } + + return intent_data_list; + } + + private boolean canScheduleExactAlarms(AlarmManager alarmManager) { + // exact scheduling supported since Android 6 + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) + return false; + if (mExactSchedulingSetting < 0) { + Bundle metaData = getAppMetadata(); + if (metaData != null) + mExactSchedulingSetting = metaData.getInt("com.unity.androidnotifications.exact_scheduling", 1); + } + if (mExactSchedulingSetting == 0) + return false; + if (Build.VERSION.SDK_INT < 31) + return true; + + return alarmManager.canScheduleExactAlarms(); + } + + public boolean canScheduleExactAlarms() { + AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + return canScheduleExactAlarms(alarmManager); + } + + // Call AlarmManager to set the broadcast intent with fire time and interval. + private void scheduleNotificationIntentAlarm(long repeatInterval, long fireTime, PendingIntent broadcast) { + AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + + if (repeatInterval <= 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && canScheduleExactAlarms(alarmManager)) { + alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, fireTime, broadcast); + } else { + alarmManager.set(AlarmManager.RTC_WAKEUP, fireTime, broadcast); + } + } else { + alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, fireTime, repeatInterval, broadcast); + } + } + + // Check the notification status by id. + public int checkNotificationStatus(int id) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + for (StatusBarNotification n : getNotificationManager().getActiveNotifications()) { + if (id == n.getId()) + return 2; + } + } else synchronized (this) { + for (Integer notificationId : mVisibleNotifications) { + if (notificationId.intValue() == id) + return 2; + } + } + + if (mScheduledNotifications.containsKey(id)) + return 1; + if (checkIfPendingNotificationIsRegistered(id)) + return 1; + + return 0; + } + + // Check if the pending notification with the given id has been registered. + public boolean checkIfPendingNotificationIsRegistered(int id) { + Intent intent = new Intent(mActivity, UnityNotificationManager.class); + return (getBroadcastPendingIntent(id, intent, PendingIntent.FLAG_NO_CREATE) != null); + } + + // Cancel all the pending notifications. + public void cancelAllPendingNotificationIntents() { + mBackgroundThread.enqueueCancelAllNotifications(); + } + + private synchronized Set getScheduledNotificationIDs() { + SharedPreferences prefs = mContext.getSharedPreferences(NOTIFICATION_IDS_SHARED_PREFS, Context.MODE_PRIVATE); + Set ids = prefs.getStringSet(NOTIFICATION_IDS_SHARED_PREFS_KEY, new HashSet()); + return ids; + } + + synchronized void saveScheduledNotificationIDs(Set ids) { + SharedPreferences.Editor editor = mContext.getSharedPreferences(NOTIFICATION_IDS_SHARED_PREFS, Context.MODE_PRIVATE).edit().clear(); + editor.putStringSet(NOTIFICATION_IDS_SHARED_PREFS_KEY, ids); + editor.apply(); + } + + // Cancel a pending notification by id. + public void cancelPendingNotification(int id) { + mBackgroundThread.enqueueCancelNotification(id); + } + + // Cancel a pending notification by id. + void cancelPendingNotificationIntent(int id) { + Intent intent = new Intent(mContext, UnityNotificationManager.class); + PendingIntent broadcast = getBroadcastPendingIntent(id, intent, PendingIntent.FLAG_NO_CREATE); + + if (broadcast != null) { + AlarmManager alarmManager = (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE); + alarmManager.cancel(broadcast); + broadcast.cancel(); + } + } + + // Delete the notification intent from SharedPreferences by id. + synchronized void deleteExpiredNotificationIntent(String id) { + SharedPreferences notificationPrefs = mContext.getSharedPreferences(getSharedPrefsNameByNotificationId(id), Context.MODE_PRIVATE); + notificationPrefs.edit().clear().apply(); + } + + // Cancel a previously shown notification by id. + public void cancelDisplayedNotification(int id) { + getNotificationManager().cancel(id); + } + + // Cancel all previously shown notifications. + public void cancelAllNotifications() { + getNotificationManager().cancelAll(); + } + + @Override + public void onReceive(Context context, Intent intent) { + // This method is called on OS created instance and that instance is recreated during various times + // for example sending app to background will cause new instance to be created when alarm fires + // since we also create one instance for our uses, always forward to that instance (creating if necessary) + getNotificationManagerImpl(context).onReceive(intent); + } + + public void onReceive(Intent intent) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) { + if (KEY_NOTIFICATION_DISMISSED.equals(intent.getAction())) { + int removedId = intent.getIntExtra(KEY_NOTIFICATION_DISMISSED, -1); + if (removedId > 0) synchronized (this) { + mVisibleNotifications.remove(removedId); + } + return; + } + } + showNotification(intent); + } + + private void showNotification(Intent intent) { + Object notification = getNotificationOrIdForIntent(intent); + if (notification == null) { + return; + } + + if (notification instanceof Notification) { + Notification notif = (Notification) notification; + int id = notif.extras.getInt(KEY_ID, -1); + notify(id, notif); + return; + } + + Integer notificationId = (Integer)notification; + Notification.Builder builder = mScheduledNotifications.get(notificationId); + if (builder != null) { + notify(notificationId, builder); + return; + } + + AsyncTask.execute(() -> { + Notification.Builder nb = deserializeNotificationBuilder(notificationId); + if (nb == null) { + Log.e(TAG_UNITY, "Failed to recover builder, can't send notification"); + return; + } + + notify(notificationId, nb); + }); + } + + void notify(int id, Notification.Builder builder) { + Class openActivity; + if (mOpenActivity == null) { + openActivity = UnityNotificationUtilities.getOpenAppActivity(mContext); + if (openActivity == null) { + Log.e(TAG_UNITY, "Activity not found, cannot show notification"); + return; + } + } + else { + openActivity = mOpenActivity; + } + + Notification notification = buildNotificationForSending(openActivity, builder); + if (notification != null) { + notify(id, notification); + } + } + + // Call the system notification service to notify the notification. + private void notify(int id, Notification notification) { + boolean showInForeground = notification.extras.getBoolean(KEY_SHOW_IN_FOREGROUND, true); + if (!isInForeground() || showInForeground) { + getNotificationManager().notify(id, notification); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) synchronized (this) { + mVisibleNotifications.add(Integer.valueOf(id)); + } + } + + long repeatInterval = notification.extras.getLong(KEY_REPEAT_INTERVAL, -1); + if (repeatInterval <= 0) { + mScheduledNotifications.remove(id); + cancelPendingNotificationIntent(id); + } + + try { + if (mNotificationCallback != null) + mNotificationCallback.onSentNotification(notification); + } catch (RuntimeException ex) { + Log.w(TAG_UNITY, "Can not invoke OnNotificationReceived event when the app is not running!"); + } + } + + public static Integer getNotificationColor(Notification notification) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) + return null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + if (!notification.extras.containsKey(Notification.EXTRA_COLORIZED)) + return null; + } + + return notification.color; + } + + public static int getNotificationGroupAlertBehavior(Notification notification) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + return notification.getGroupAlertBehavior(); + return 0; + } + + private void finalizeNotificationForDisplay(Notification.Builder notificationBuilder) { + String icon = notificationBuilder.getExtras().getString(KEY_SMALL_ICON); + Object ico = getIconForUri(icon); + if (ico != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + notificationBuilder.setSmallIcon((Icon)ico); + } else { + int iconId = UnityNotificationUtilities.findResourceIdInContextByName(mContext, icon); + if (iconId == 0) { + iconId = mContext.getApplicationInfo().icon; + } + notificationBuilder.setSmallIcon(iconId); + } + + icon = notificationBuilder.getExtras().getString(KEY_LARGE_ICON); + Object largeIcon = getIcon(icon); + if (largeIcon != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && largeIcon instanceof Icon) + notificationBuilder.setLargeIcon((Icon)largeIcon); + else + notificationBuilder.setLargeIcon((Bitmap)largeIcon); + } + + setupBigPictureStyle(notificationBuilder); + } + + private Object getIcon(String icon) { + if (icon == null || icon.length() == 0) + return null; + if (icon.charAt(0) == '/') { + BitmapFactory.decodeFile(icon); + } + + Object ico = getIconForUri(icon); + if (ico != null) + return ico; + + return getIconFromResources(icon, false); + } + + private Object getIconForUri(String uri) { + if (uri == null || uri.length() == 0) + return null; + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && uri.indexOf("://") > 0) { + return Icon.createWithContentUri(uri); + } + + return null; + } + + private Object getIconFromResources(String name, boolean forceBitmap) { + int iconId = UnityNotificationUtilities.findResourceIdInContextByName(mContext, name); + if (iconId != 0) { + if (!forceBitmap && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) + return Icon.createWithResource(mContext, iconId); + return BitmapFactory.decodeResource(mContext.getResources(), iconId); + } + + return null; + } + + private Bitmap loadBitmap(String uri) { + try { + InputStream in = mContext.getContentResolver().openInputStream(Uri.parse(uri)); + return BitmapFactory.decodeStream(in); + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to load image " + uri, e); + return null; + } + } + + @SuppressWarnings("deprecation") + public Notification.Builder createNotificationBuilder(String channelID) { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + Notification.Builder notificationBuilder = new Notification.Builder(mContext); + + // For device below Android O, we use the values from NotificationChannelWrapper to set visibility, priority etc. + NotificationChannelWrapper fakeNotificationChannel = getNotificationChannel(channelID); + + if (fakeNotificationChannel.vibrationPattern != null && fakeNotificationChannel.vibrationPattern.length > 0) { + notificationBuilder.setDefaults(Notification.DEFAULT_LIGHTS | Notification.DEFAULT_SOUND); + notificationBuilder.setVibrate(fakeNotificationChannel.vibrationPattern); + } else { + notificationBuilder.setDefaults(Notification.DEFAULT_ALL); + } + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + notificationBuilder.setVisibility((int) fakeNotificationChannel.lockscreenVisibility); + } + + // Need to convert Oreo channel importance to pre-Oreo priority. + int priority; + switch (fakeNotificationChannel.importance) { + case NotificationManager.IMPORTANCE_HIGH: + priority = Notification.PRIORITY_MAX; + break; + case NotificationManager.IMPORTANCE_DEFAULT: + priority = Notification.PRIORITY_DEFAULT; + break; + case NotificationManager.IMPORTANCE_LOW: + priority = Notification.PRIORITY_LOW; + break; + case NotificationManager.IMPORTANCE_NONE: + priority = Notification.PRIORITY_MIN; + break; + default: + priority = Notification.PRIORITY_DEFAULT; + } + notificationBuilder.setPriority(priority); + notificationBuilder.getExtras().putString(KEY_CHANNEL_ID, channelID); + + return notificationBuilder; + } else { + return new Notification.Builder(mContext, channelID); + } + } + + public static void setNotificationIcon(Notification.Builder notificationBuilder, String keyName, String icon) { + if (icon == null || icon.length() == 0 && notificationBuilder.getExtras().getString(keyName) != null) + notificationBuilder.getExtras().remove(keyName); + else + notificationBuilder.getExtras().putString(keyName, icon); + } + + public void setupBigPictureStyle(Notification.Builder builder, + String largeIcon, String picture, String contentTitle, String contentDescription, String summaryText, boolean showWhenCollapsed) { + Bundle extras = builder.getExtras(); + if (picture == null || picture.length() == 0) + return; + extras.putString(KEY_BIG_LARGE_ICON, largeIcon); + extras.putString(KEY_BIG_PICTURE, picture); + extras.putString(KEY_BIG_CONTENT_TITLE, contentTitle); + extras.putString(KEY_BIG_SUMMARY_TEXT, summaryText); + extras.putString(KEY_BIG_CONTENT_DESCRIPTION, contentDescription); + extras.putBoolean(KEY_BIG_SHOW_WHEN_COLLAPSED, showWhenCollapsed); + } + + private void setupBigPictureStyle(Notification.Builder builder) { + Bundle extras = builder.getExtras(); + String picture = extras.getString(KEY_BIG_PICTURE); + if (picture == null) + return; // not big picture style + Notification.BigPictureStyle style = new Notification.BigPictureStyle(); + String largeIcon = extras.getString(KEY_BIG_LARGE_ICON); + Object ico = getIcon(largeIcon); + if (ico != null) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ico instanceof Icon) + style.bigLargeIcon((Icon)ico); + else + style.bigLargeIcon((Bitmap)ico); + } + + if (picture.charAt(0) == '/') { + style.bigPicture(BitmapFactory.decodeFile(picture)); + } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && picture.indexOf("://") > 0) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + Icon icon = Icon.createWithContentUri(picture); + style.bigPicture(icon); + } else { + Bitmap pic = loadBitmap(picture); + if (pic != null) { + style.bigPicture(pic); + } + } + } else { + Object pic = getIconFromResources(picture, Build.VERSION.SDK_INT < Build.VERSION_CODES.S); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S && pic instanceof Icon) + style.bigPicture((Icon)pic); + else if (pic instanceof Bitmap) + style.bigPicture((Bitmap)pic); + } + + style.setBigContentTitle(extras.getString(KEY_BIG_CONTENT_TITLE)); + style.setSummaryText(extras.getString(KEY_BIG_SUMMARY_TEXT)); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { + style.setContentDescription(extras.getString(KEY_BIG_CONTENT_DESCRIPTION)); + style.showBigPictureWhenCollapsed(extras.getBoolean(KEY_BIG_SHOW_WHEN_COLLAPSED, false)); + } + + builder.setStyle(style); + } + + public static void setNotificationColor(Notification.Builder notificationBuilder, int color) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + if (color != 0) { + notificationBuilder.setColor(color); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + notificationBuilder.setColorized(true); + } + } + } + } + + public static void setNotificationUsesChronometer(Notification.Builder notificationBuilder, boolean usesChrono) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) + notificationBuilder.setUsesChronometer(usesChrono); + } + + public static void setNotificationGroupAlertBehavior(Notification.Builder notificationBuilder, int behavior) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) + notificationBuilder.setGroupAlertBehavior(behavior); + } + + public static String getNotificationChannelId(Notification notification) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + return notification.getChannelId(); + } + + return null; + } + + private static boolean isInForeground() { + ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo(); + ActivityManager.getMyMemoryState(appProcessInfo); + return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE); + } + + public Notification getNotificationFromIntent(Intent intent) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + if (intent.hasExtra(KEY_NOTIFICATION_ID)) { + int id = intent.getExtras().getInt(KEY_NOTIFICATION_ID); + StatusBarNotification[] shownNotifications = getNotificationManager().getActiveNotifications(); + for (StatusBarNotification n : shownNotifications) { + if (n.getId() == id) { + return n.getNotification(); + } + } + } + } + + Object notification = getNotificationOrBuilderForIntent(intent); + if (notification == null) + return null; + if (notification instanceof Notification) + return (Notification)notification; + Notification.Builder builder = (Notification.Builder)notification; + return builder.build(); + } + + private Object getNotificationOrIdForIntent(Intent intent) { + if (intent.hasExtra(KEY_NOTIFICATION_ID)) { + return intent.getExtras().getInt(KEY_NOTIFICATION_ID); + } else if (intent.hasExtra(KEY_NOTIFICATION)) { + // old code path where Notification object is in intent + // in case the app was replaced and there still are pending alarms with notification + return intent.getParcelableExtra(KEY_NOTIFICATION); + } + + return null; + } + + private Object getNotificationOrBuilderForIntent(Intent intent) { + Object notification = getNotificationOrIdForIntent(intent); + if (notification instanceof Integer) { + Integer notificationId = (Integer)notification; + if ((notification = mScheduledNotifications.get(notificationId)) == null) { + // in case we don't have cached notification, deserialize from storage + return deserializeNotificationBuilder(notificationId); + } + } + + return notification; + } + + private Notification.Builder deserializeNotificationBuilder(Integer notificationId) { + SharedPreferences prefs = mContext.getSharedPreferences(getSharedPrefsNameByNotificationId(notificationId.toString()), Context.MODE_PRIVATE); + Object notification = UnityNotificationUtilities.deserializeNotification(mContext, prefs); + if (notification == null) { + return null; + } + + if (notification instanceof Notification) { + return UnityNotificationUtilities.recoverBuilder(mContext, (Notification)notification); + } + + return (Notification.Builder)notification; + } + + public void showNotificationSettings(String channelId) { + Intent settingsIntent; + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) { + settingsIntent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); + Uri uri = Uri.fromParts("package", mContext.getPackageName(), null); + settingsIntent.setData(uri); + } else { + if (channelId != null && channelId.length() > 0) { + settingsIntent = new Intent(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS); + settingsIntent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId); + } else { + settingsIntent = new Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS); + } + + settingsIntent.putExtra(Settings.EXTRA_APP_PACKAGE, mContext.getPackageName()); + } + + settingsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + mActivity.startActivity(settingsIntent); + } +} + +// Provide a wrapper for NotificationChannel. +// Create this wrapper for all Android versions as NotificationChannel is only available for Android O or above. +class NotificationChannelWrapper { + public String id; + public String name; + public int importance; + public String description; + public boolean enableLights; + public boolean enableVibration; + public boolean canBypassDnd; + public boolean canShowBadge; + public long[] vibrationPattern; + public int lockscreenVisibility; + public String group; +} + +// Implemented in C# to receive callback on notification show +interface NotificationCallback { + void onSentNotification(Notification notification); +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationRestartOnBootReceiver.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationRestartOnBootReceiver.java new file mode 100755 index 000000000..70774514b --- /dev/null +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationRestartOnBootReceiver.java @@ -0,0 +1,67 @@ +package com.unity.androidnotifications; + +import android.app.Notification; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.os.AsyncTask; +import android.os.Bundle; +import android.util.Log; + +import java.util.Calendar; +import java.util.Date; +import java.util.List; + +import static com.unity.androidnotifications.UnityNotificationManager.KEY_FIRE_TIME; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_ID; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_REPEAT_INTERVAL; +import static com.unity.androidnotifications.UnityNotificationManager.TAG_UNITY; + +public class UnityNotificationRestartOnBootReceiver extends BroadcastReceiver { + private static final long EXPIRATION_TRESHOLD = 600000; // 10 minutes + + @Override + public void onReceive(Context context, Intent received_intent) { + Log.d(TAG_UNITY, "Rescheduling notifications after restart"); + if (Intent.ACTION_BOOT_COMPLETED.equals(received_intent.getAction())) { + AsyncTask.execute(() -> { rescheduleSavedNotifications(context); }); + } + } + + private static void rescheduleSavedNotifications(Context context) { + UnityNotificationManager manager = UnityNotificationManager.getNotificationManagerImpl(context); + List saved_notifications = manager.loadSavedNotifications(); + Date currentDate = Calendar.getInstance().getTime(); + + for (Notification.Builder notificationBuilder : saved_notifications) { + rescheduleNotification(manager, currentDate, notificationBuilder); + } + } + + private static boolean rescheduleNotification(UnityNotificationManager manager, Date currentDate, Notification.Builder notificationBuilder) { + try { + Bundle extras = notificationBuilder.getExtras(); + long repeatInterval = extras.getLong(KEY_REPEAT_INTERVAL, 0L); + long fireTime = extras.getLong(KEY_FIRE_TIME, 0L); + Date fireTimeDate = new Date(fireTime); + + boolean isRepeatable = repeatInterval > 0; + + if (fireTimeDate.after(currentDate) || isRepeatable) { + manager.scheduleAlarmWithNotification(notificationBuilder); + return true; + } else if (currentDate.getTime() - fireTime < EXPIRATION_TRESHOLD) { + // notification is in the past, but not by much, send now + int id = extras.getInt(KEY_ID); + manager.notify(id, notificationBuilder); + return true; + } else { + Log.d(TAG_UNITY, "Notification expired, not rescheduling, ID: " + extras.getInt(KEY_ID, -1)); + return false; + } + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to reschedule notification", e); + return false; + } + } +} diff --git a/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationUtilities.java b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationUtilities.java new file mode 100755 index 000000000..2adefc2cd --- /dev/null +++ b/BFVersions/android/google_common/unityLibrary/src/main/java/com/unity/androidnotifications/UnityNotificationUtilities.java @@ -0,0 +1,654 @@ +package com.unity.androidnotifications; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.charset.StandardCharsets; + +import android.app.Notification; +import android.content.Context; +import android.content.Intent; +import android.content.SharedPreferences; +import android.content.pm.ActivityInfo; +import android.content.pm.ApplicationInfo; +import android.content.pm.PackageManager; +import android.content.res.Resources; +import android.os.Build; +import android.os.Bundle; +import android.os.Parcel; +import android.os.Parcelable; +import android.util.Base64; +import android.util.Log; + +import static com.unity.androidnotifications.UnityNotificationManager.KEY_CHANNEL_ID; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_FIRE_TIME; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_ID; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_INTENT_DATA; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_LARGE_ICON; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_NOTIFICATION; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_REPEAT_INTERVAL; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_SMALL_ICON; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_SHOW_IN_FOREGROUND; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_LARGE_ICON; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_PICTURE; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_CONTENT_TITLE; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_SUMMARY_TEXT; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_CONTENT_DESCRIPTION; +import static com.unity.androidnotifications.UnityNotificationManager.KEY_BIG_SHOW_WHEN_COLLAPSED; +import static com.unity.androidnotifications.UnityNotificationManager.TAG_UNITY; + +class UnityNotificationUtilities { + /* + We serialize notifications and save them to shared prefs, so that if app is killed, we can recreate them. + The serialized BLOB starts with a four byte magic number descibing serialization type, followed by an integer version. + IMPORTANT: IF YOU DO A CHANGE THAT AFFECTS THE LAYOUT, BUMP THE VERSION, AND ENSURE OLD VERSION STILL DESERIALIZES. ADD TEST. + In real life app can get updated having old serialized notifications present, so we should be able to deserialize them. + */ + // magic stands for "Unity Mobile Notifications Notification" + static final byte[] UNITY_MAGIC_NUMBER = new byte[] { 'U', 'M', 'N', 'N'}; + private static final byte[] UNITY_MAGIC_NUMBER_PARCELLED = new byte[] { 'U', 'M', 'N', 'P'}; + private static final int NOTIFICATION_SERIALIZATION_VERSION = 3; + private static final int INTENT_SERIALIZATION_VERSION = 0; + + static final String SAVED_NOTIFICATION_PRIMARY_KEY = "data"; + static final String SAVED_NOTIFICATION_FALLBACK_KEY = "fallback.data"; + + protected static int findResourceIdInContextByName(Context context, String name) { + if (name == null) + return 0; + + try { + Resources res = context.getResources(); + if (res != null) { + int id = res.getIdentifier(name, "mipmap", context.getPackageName()); + if (id == 0) + return res.getIdentifier(name, "drawable", context.getPackageName()); + else + return id; + } + return 0; + } catch (Resources.NotFoundException e) { + return 0; + } + } + + /* Originally we used to serialize a bundle with predefined list of values. + After we exposed entire Notification.Builder to users, this is not sufficient anymore. + Unfortunately, while Notification itself is Parcelable and can be marshalled to bytes, + it's contents are not guaranteed to be (Binder objects). + Hence what we try to do here is: + - serialize as is if notification is possibly customized by user + - otherwise serialize our stuff, since there is nothing more + */ + protected static void serializeNotification(SharedPreferences prefs, Notification notification, boolean serializeParcel) { + try { + String serialized; + ByteArrayOutputStream data = new ByteArrayOutputStream(); + DataOutputStream out = new DataOutputStream(data); + if (serializeParcel) { + Intent intent = new Intent(); + intent.putExtra(KEY_NOTIFICATION, notification); + if (serializeNotificationParcel(intent, out)) { + out.close(); + byte[] bytes = data.toByteArray(); + serialized = Base64.encodeToString(bytes, 0, bytes.length, 0); + } else { + return; // failed + } + } + else { + if (serializeNotificationCustom(notification, out)) { + out.flush(); + byte[] bytes = data.toByteArray(); + serialized = Base64.encodeToString(bytes, 0, bytes.length, 0); + } else { + return; // failed + } + } + + SharedPreferences.Editor editor = prefs.edit().clear(); + editor.putString(SAVED_NOTIFICATION_PRIMARY_KEY, serialized); + editor.apply(); + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to serialize notification", e); + } + } + + static boolean serializeNotificationParcel(Intent intent, DataOutputStream out) { + try { + byte[] bytes = serializeParcelable(intent); + if (bytes == null || bytes.length == 0) + return false; + out.write(UNITY_MAGIC_NUMBER_PARCELLED); + out.writeInt(INTENT_SERIALIZATION_VERSION); + out.writeInt(bytes.length); + out.write(bytes); + return true; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to serialize notification as Parcel", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to serialize notification as Parcel", e); + } + + return false; + } + + private static boolean serializeNotificationCustom(Notification notification, DataOutputStream out) { + try { + out.write(UNITY_MAGIC_NUMBER); + out.writeInt(NOTIFICATION_SERIALIZATION_VERSION); + + // serialize extras + boolean showWhen = notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false); + + out.writeInt(notification.extras.getInt(KEY_ID)); + serializeString(out, notification.extras.getString(Notification.EXTRA_TITLE)); + serializeString(out, notification.extras.getString(Notification.EXTRA_TEXT)); + serializeString(out, notification.extras.getString(KEY_SMALL_ICON)); + serializeString(out, notification.extras.getString(KEY_LARGE_ICON)); + out.writeLong(notification.extras.getLong(KEY_FIRE_TIME, -1)); + out.writeLong(notification.extras.getLong(KEY_REPEAT_INTERVAL, -1)); + serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : notification.extras.getString(Notification.EXTRA_BIG_TEXT)); + out.writeBoolean(notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false)); + out.writeBoolean(showWhen); + serializeString(out, notification.extras.getString(KEY_INTENT_DATA)); + out.writeBoolean(notification.extras.getBoolean(KEY_SHOW_IN_FOREGROUND, true)); + + String bigPicture = notification.extras.getString(KEY_BIG_PICTURE); + serializeString(out, bigPicture); + if (bigPicture != null && bigPicture.length() > 0) { + // the following only need to be put in if big picture is there + serializeString(out, notification.extras.getString(KEY_BIG_LARGE_ICON)); + serializeString(out, notification.extras.getString(KEY_BIG_CONTENT_TITLE)); + serializeString(out, notification.extras.getString(KEY_BIG_CONTENT_DESCRIPTION)); + serializeString(out, notification.extras.getString(KEY_BIG_SUMMARY_TEXT)); + out.writeBoolean(notification.extras.getBoolean(KEY_BIG_SHOW_WHEN_COLLAPSED, false)); + } + + serializeString(out, Build.VERSION.SDK_INT < Build.VERSION_CODES.O ? null : notification.getChannelId()); + Integer color = UnityNotificationManager.getNotificationColor(notification); + out.writeBoolean(color != null); + if (color != null) + out.writeInt(color); + out.writeInt(notification.number); + out.writeBoolean(0 != (notification.flags & Notification.FLAG_AUTO_CANCEL)); + serializeString(out, notification.getGroup()); + out.writeBoolean(0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY)); + out.writeInt(UnityNotificationManager.getNotificationGroupAlertBehavior(notification)); + serializeString(out, notification.getSortKey()); + if (showWhen) + out.writeLong(notification.when); + + return true; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to serialize notification", e); + return false; + } + } + + static void serializeString(DataOutputStream out, String s) throws IOException { + if (s == null || s.length() == 0) + out.writeInt(0); + else { + byte[] bytes = s.getBytes(StandardCharsets.UTF_8); + out.writeInt(bytes.length); + out.write(bytes); + } + } + + static byte[] serializeParcelable(Parcelable obj) { + try { + Parcel p = Parcel.obtain(); + Bundle b = new Bundle(); + b.putParcelable("obj", obj); + p.writeParcelable(b, 0); + byte[] result = p.marshall(); + p.recycle(); + return result; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to serialize Parcelable", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to serialize Parcelable", e); + } + + return null; + } + + protected static Object deserializeNotification(Context context, SharedPreferences prefs) { + String serializedIntentData = prefs.getString(SAVED_NOTIFICATION_PRIMARY_KEY, ""); + if (null == serializedIntentData || serializedIntentData.length() <= 0) + return null; + byte[] bytes = Base64.decode(serializedIntentData, 0); + Object notification = deserializeNotification(context, bytes); + if (notification != null) + return notification; + serializedIntentData = prefs.getString(SAVED_NOTIFICATION_FALLBACK_KEY, ""); + if (null == serializedIntentData || serializedIntentData.length() <= 0) + return null; + bytes = Base64.decode(serializedIntentData, 0); + return deserializeNotification(context, bytes); + } + + /* See serialization method above for explaination of fallbacks. + This one matches it with one additional fallback: support for "old" bundle serialization. + */ + private static Object deserializeNotification(Context context, byte[] bytes) { + ByteArrayInputStream data = new ByteArrayInputStream(bytes); + DataInputStream in = new DataInputStream(data); + Notification notification = deserializeNotificationParcelable(in); + if (notification != null) + return notification; + data.reset(); + Notification.Builder builder = deserializeNotificationCustom(context, in); + if (builder == null) { + builder = deserializedFromOldIntent(context, bytes); + } + return builder; + } + + private static boolean readAndCheckMagicNumber(DataInputStream in, byte[] magic) { + try { + boolean magicNumberMatch = true; + for (int i = 0; i < magic.length; ++i) { + byte b = in.readByte(); + if (b != magic[i]) { + magicNumberMatch = false; + break; + } + } + + return magicNumberMatch; + } catch (Exception e) { + return false; + } + } + + private static Notification deserializeNotificationParcelable(DataInputStream in) { + try { + if (!readAndCheckMagicNumber(in, UNITY_MAGIC_NUMBER_PARCELLED)) + return null; + int version = in.readInt(); + if (version < 0 || version > INTENT_SERIALIZATION_VERSION) + return null; + Intent intent = deserializeParcelable(in); + Notification notification = intent.getParcelableExtra(KEY_NOTIFICATION); + return notification; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to deserialize notification intent", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to deserialize notification intent", e); + } + + return null; + } + + private static Notification.Builder deserializeNotificationCustom(Context context, DataInputStream in) { + try { + if (!readAndCheckMagicNumber(in, UNITY_MAGIC_NUMBER)) + return null; + int version = in.readInt(); + if (version < 0 || version > NOTIFICATION_SERIALIZATION_VERSION) + return null; + + // deserialize extras + int id = 0; + String title, text, smallIcon, largeIcon, bigText, intentData; + long fireTime, repeatInterval; + boolean usesStopWatch, showWhen, showInForeground = true; + Bundle extras = null; + String bigPicture = null, bigLargeIcon = null, bigContentTitle = null, bigSummary = null, bigContentDesc = null; + boolean bigShowWhenCollapsed = false; + if (version < 2) { + // no longer serialized since v2 + extras = deserializeParcelable(in); + } + + // before v2 it was extras or variables, since 2 always variables + if (extras == null) { + // extras serialized manually + id = in.readInt(); + title = deserializeString(in); + text = deserializeString(in); + smallIcon = deserializeString(in); + largeIcon = deserializeString(in); + fireTime = in.readLong(); + repeatInterval = in.readLong(); + bigText = deserializeString(in); + usesStopWatch = in.readBoolean(); + showWhen = in.readBoolean(); + intentData = deserializeString(in); + if (version > 0) + showInForeground = in.readBoolean(); + + if (version >= 3) { + bigPicture = deserializeString(in); + if (bigPicture != null && bigPicture.length() > 0) { + // the following only need to be put in if big picture is there + bigLargeIcon = deserializeString(in); + bigContentTitle = deserializeString(in); + bigContentDesc = deserializeString(in); + bigSummary = deserializeString(in); + bigShowWhenCollapsed = in.readBoolean(); + } + } + } else { + title = extras.getString(Notification.EXTRA_TITLE); + text = extras.getString(Notification.EXTRA_TEXT); + smallIcon = extras.getString(KEY_SMALL_ICON); + largeIcon = extras.getString(KEY_LARGE_ICON); + fireTime = extras.getLong(KEY_FIRE_TIME, -1); + repeatInterval = extras.getLong(KEY_REPEAT_INTERVAL, -1); + bigText = Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP ? null : extras.getString(Notification.EXTRA_BIG_TEXT); + usesStopWatch = extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false); + showWhen = extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false); + intentData = extras.getString(KEY_INTENT_DATA); + } + + String channelId = deserializeString(in); + boolean haveColor = in.readBoolean(); + int color = 0; + if (haveColor) + color = in.readInt(); + int number = in.readInt(); + boolean shouldAutoCancel = in.readBoolean(); + String group = deserializeString(in); + boolean groupSummary = in.readBoolean(); + int groupAlertBehavior = in.readInt(); + String sortKey = deserializeString(in); + long when = showWhen ? in.readLong() : 0; + + UnityNotificationManager manager = UnityNotificationManager.getNotificationManagerImpl(context); + Notification.Builder builder = manager.createNotificationBuilder(channelId); + if (extras != null) + builder.setExtras(extras); + else { + builder.getExtras().putInt(KEY_ID, id); + UnityNotificationManager.setNotificationIcon(builder, KEY_SMALL_ICON, smallIcon); + UnityNotificationManager.setNotificationIcon(builder, KEY_LARGE_ICON, largeIcon); + if (fireTime != -1) + builder.getExtras().putLong(KEY_FIRE_TIME, fireTime); + if (repeatInterval != -1) + builder.getExtras().putLong(KEY_REPEAT_INTERVAL, repeatInterval); + if (intentData != null) + builder.getExtras().putString(KEY_INTENT_DATA, intentData); + builder.getExtras().putBoolean(KEY_SHOW_IN_FOREGROUND, showInForeground); + } + if (title != null) + builder.setContentTitle(title); + if (text != null) + builder.setContentText(text); + if (bigText != null) + builder.setStyle(new Notification.BigTextStyle().bigText(bigText)); + else if (bigPicture != null) + manager.setupBigPictureStyle(builder, bigLargeIcon, bigPicture, bigContentTitle, bigContentDesc, bigSummary, bigShowWhenCollapsed); + if (haveColor) + UnityNotificationManager.setNotificationColor(builder, color); + if (number >= 0) + builder.setNumber(number); + builder.setAutoCancel(shouldAutoCancel); + UnityNotificationManager.setNotificationUsesChronometer(builder, usesStopWatch); + if (group != null && group.length() > 0) + builder.setGroup(group); + builder.setGroupSummary(groupSummary); + UnityNotificationManager.setNotificationGroupAlertBehavior(builder, groupAlertBehavior); + if (sortKey != null && sortKey.length() > 0) + builder.setSortKey(sortKey); + if (showWhen) { + builder.setShowWhen(true); + builder.setWhen(when); + } + + return builder; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to deserialize notification", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to deserialize notification", e); + } + + return null; + } + + private static Notification.Builder deserializedFromOldIntent(Context context, byte[] bytes) { + try { + Parcel p = Parcel.obtain(); + p.unmarshall(bytes, 0, bytes.length); + p.setDataPosition(0); + Bundle bundle = new Bundle(); + bundle.readFromParcel(p); + + int id = bundle.getInt(KEY_ID, -1); + String channelId = bundle.getString("channelID"); + String textTitle = bundle.getString("textTitle"); + String textContent = bundle.getString("textContent"); + String smallIcon = bundle.getString("smallIconStr"); + boolean autoCancel = bundle.getBoolean("autoCancel", false); + boolean usesChronometer = bundle.getBoolean("usesChronometer", false); + long fireTime = bundle.getLong(KEY_FIRE_TIME, -1); + long repeatInterval = bundle.getLong(KEY_REPEAT_INTERVAL, -1); + String largeIcon = bundle.getString("largeIconStr"); + int style = bundle.getInt("style", -1); + int color = bundle.getInt("color", 0); + int number = bundle.getInt("number", 0); + String intentData = bundle.getString(KEY_INTENT_DATA); + String group = bundle.getString("group"); + boolean groupSummary = bundle.getBoolean("groupSummary", false); + String sortKey = bundle.getString("sortKey"); + int groupAlertBehaviour = bundle.getInt("groupAlertBehaviour", -1); + boolean showTimestamp = bundle.getBoolean("showTimestamp", false); + + Notification.Builder builder = UnityNotificationManager.getNotificationManagerImpl(context).createNotificationBuilder(channelId); + builder.getExtras().putInt(KEY_ID, id); + builder.setContentTitle(textTitle); + builder.setContentText(textContent); + UnityNotificationManager.setNotificationIcon(builder, KEY_SMALL_ICON, smallIcon); + builder.setAutoCancel(autoCancel); + builder.setUsesChronometer(usesChronometer); + builder.getExtras().putLong(KEY_FIRE_TIME, fireTime); + builder.getExtras().putLong(KEY_REPEAT_INTERVAL, repeatInterval); + UnityNotificationManager.setNotificationIcon(builder, KEY_LARGE_ICON, largeIcon); + if (style == 2) + builder.setStyle(new Notification.BigTextStyle().bigText(textContent)); + if (color != 0) + UnityNotificationManager.setNotificationColor(builder, color); + if (number >= 0) + builder.setNumber(number); + if (intentData != null) + builder.getExtras().putString(KEY_INTENT_DATA, intentData); + if (null != group && group.length() > 0) + builder.setGroup(group); + builder.setGroupSummary(groupSummary); + if (null != sortKey && sortKey.length() > 0) + builder.setSortKey(sortKey); + UnityNotificationManager.setNotificationGroupAlertBehavior(builder, groupAlertBehaviour); + builder.setShowWhen(showTimestamp); + return builder; + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to deserialize old style notification", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to deserialize old style notification", e); + } + + return null; + } + + private static String deserializeString(DataInputStream in) throws IOException { + int length = in.readInt(); + if (length <= 0) + return null; + byte[] bytes = new byte[length]; + int didRead = in.read(bytes); + if (didRead != bytes.length) + throw new IOException("Insufficient amount of bytes read"); + return new String(bytes, StandardCharsets.UTF_8); + } + + private static T deserializeParcelable(DataInputStream in) throws IOException { + int length = in.readInt(); + if (length <= 0) + return null; + byte[] bytes = new byte[length]; + int didRead = in.read(bytes); + if (didRead != bytes.length) + throw new IOException("Insufficient amount of bytes read"); + + try { + Parcel p = Parcel.obtain(); + p.unmarshall(bytes, 0, bytes.length); + p.setDataPosition(0); + Bundle b = p.readParcelable(UnityNotificationUtilities.class.getClassLoader()); + p.recycle(); + if (b != null) { + return b.getParcelable("obj"); + } + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to deserialize parcelable", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to deserialize parcelable", e); + } + + return null; + } + + // Returns Activity class to be opened when notification is tapped + // Search is done in this order: + // * class specified in meta-data key custom_notification_android_activity + // * the only enabled activity with name ending in either .UnityPlayerActivity or .UnityPlayerGameActivity + // * the only enabled activity in the package + protected static Class getOpenAppActivity(Context context) { + try { + PackageManager pm = context.getPackageManager(); + ApplicationInfo ai = pm.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA); + Bundle bundle = ai.metaData; + + if (bundle.containsKey("custom_notification_android_activity")) { + try { + return Class.forName(bundle.getString("custom_notification_android_activity")); + } catch (ClassNotFoundException e) { + Log.e(TAG_UNITY, "Specified activity class for notifications not found: " + e.getMessage()); + } + } + + Log.w(TAG_UNITY, "No custom_notification_android_activity found, attempting to find app activity class"); + + ActivityInfo[] aInfo = pm.getPackageInfo(context.getPackageName(), PackageManager.GET_ACTIVITIES).activities; + if (aInfo == null) { + Log.e(TAG_UNITY, "Could not get package activities"); + return null; + } + + String activityClassName = null; + boolean activityIsUnity = false, activityConflict = false; + for (ActivityInfo info : aInfo) { + // activity alias not supported + if (!info.enabled || info.targetActivity != null) + continue; + + boolean candidateIsUnity = isUnityActivity(info.name); + if (activityClassName == null) { + activityClassName = info.name; + activityIsUnity = candidateIsUnity; + continue; + } + + // two Unity activities is a hard conflict + // two non-Unity activities is a conflict unless we find a Unity activity later on + if (activityIsUnity == candidateIsUnity) { + activityConflict = true; + if (activityIsUnity && candidateIsUnity) + break; + continue; + } + + if (candidateIsUnity) { + activityClassName = info.name; + activityIsUnity = candidateIsUnity; + activityConflict = false; + } + } + + if (activityConflict) { + Log.e(TAG_UNITY, "Multiple choices for activity for notifications, set activity explicitly in Notification Settings"); + return null; + } + + if (activityClassName == null) { + Log.e(TAG_UNITY, "Activity class for notifications not found"); + return null; + } + + return Class.forName(activityClassName); + } catch (PackageManager.NameNotFoundException e) { + e.printStackTrace(); + } catch (ClassNotFoundException e) { + Log.e(TAG_UNITY, "Failed to find activity class: " + e.getMessage()); + } + + return null; + } + + private static boolean isUnityActivity(String name) { + return name.endsWith(".UnityPlayerActivity") || name.endsWith(".UnityPlayerGameActivity"); + } + + protected static Notification.Builder recoverBuilder(Context context, Notification notification) { + try { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + Notification.Builder builder = Notification.Builder.recoverBuilder(context, notification); + // extras not recovered, transfer manually + builder.setExtras(notification.extras); + return builder; + } + } catch (Exception e) { + Log.e(TAG_UNITY, "Failed to recover builder for notification!", e); + } catch (OutOfMemoryError e) { + Log.e(TAG_UNITY, "Failed to recover builder for notification!", e); + } + + return recoverBuilderCustom(context, notification); + } + + private static Notification.Builder recoverBuilderCustom(Context context, Notification notification) { + String channelID = notification.extras.getString(KEY_CHANNEL_ID); + Notification.Builder builder = UnityNotificationManager.getNotificationManagerImpl(context).createNotificationBuilder(channelID); + UnityNotificationManager.setNotificationIcon(builder, KEY_SMALL_ICON, notification.extras.getString(KEY_SMALL_ICON)); + String largeIcon = notification.extras.getString(KEY_LARGE_ICON); + if (largeIcon != null && !largeIcon.isEmpty()) + UnityNotificationManager.setNotificationIcon(builder, KEY_LARGE_ICON, largeIcon); + builder.setContentTitle(notification.extras.getString(Notification.EXTRA_TITLE)); + builder.setContentText(notification.extras.getString(Notification.EXTRA_TEXT)); + builder.setAutoCancel(0 != (notification.flags & Notification.FLAG_AUTO_CANCEL)); + if (notification.number >= 0) + builder.setNumber(notification.number); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { + String bigText = notification.extras.getString(Notification.EXTRA_BIG_TEXT); + if (bigText != null) + builder.setStyle(new Notification.BigTextStyle().bigText(bigText)); + } + + builder.setWhen(notification.when); + String group = notification.getGroup(); + if (group != null && !group.isEmpty()) + builder.setGroup(group); + builder.setGroupSummary(0 != (notification.flags & Notification.FLAG_GROUP_SUMMARY)); + String sortKey = notification.getSortKey(); + if (sortKey != null && !sortKey.isEmpty()) + builder.setSortKey(sortKey); + builder.setShowWhen(notification.extras.getBoolean(Notification.EXTRA_SHOW_WHEN, false)); + Integer color = UnityNotificationManager.getNotificationColor(notification); + if (color != null) + UnityNotificationManager.setNotificationColor(builder, color); + UnityNotificationManager.setNotificationUsesChronometer(builder, notification.extras.getBoolean(Notification.EXTRA_SHOW_CHRONOMETER, false)); + UnityNotificationManager.setNotificationGroupAlertBehavior(builder, UnityNotificationManager.getNotificationGroupAlertBehavior(notification)); + + builder.getExtras().putInt(KEY_ID, notification.extras.getInt(KEY_ID, 0)); + builder.getExtras().putLong(KEY_REPEAT_INTERVAL, notification.extras.getLong(KEY_REPEAT_INTERVAL, 0)); + builder.getExtras().putLong(KEY_FIRE_TIME, notification.extras.getLong(KEY_FIRE_TIME, 0)); + String intentData = notification.extras.getString(KEY_INTENT_DATA); + if (intentData != null && !intentData.isEmpty()) + builder.getExtras().putString(KEY_INTENT_DATA, intentData); + + return builder; + } +} diff --git a/BFVersions/android/keystore/dz_keystore.jks b/BFVersions/android/keystore/dz_keystore.jks new file mode 100755 index 000000000..04d1eadd1 Binary files /dev/null and b/BFVersions/android/keystore/dz_keystore.jks differ diff --git a/BFVersions/android/keystore/dz_keystore.txt b/BFVersions/android/keystore/dz_keystore.txt new file mode 100755 index 000000000..08141cc14 --- /dev/null +++ b/BFVersions/android/keystore/dz_keystore.txt @@ -0,0 +1 @@ +juzu_dz0! \ No newline at end of file