1. The steps for laya are the same as those for packaging other apk.
Special attention needs to be paid to:
Attached Xiaomi SDK privacy agreement to the game privacy agreement: This game is connected to Xiaomi game services
SDK, providing login and payment and real-name services. Please read the "Xiaomi Game Service Privacy Policy" for the information collected.
https://privacy.mi.com/xiaomigame-sdk/zh_CN/
Regarding the privacy agreement, the work that Android engineering needs to do:
Privacy Agreement When the user opens the game for the first time, the relevant privacy agreement needs to be displayed. After the user selects it, call
2.android project, sdk initialization:
Development environment and version requirements:
1. To connect to the SDK, the game also needs to rely on Android Support V4, version 27.1.1 or above.
2.Andoird Studio recommends 3.0.0 or above, Gradle recommends 3.6.3 or above, and JDK recommends 1.8
3.targetSdkVersion requires >=26
4.minSdkVersion recommended>=18, compileSdkVersion recommended>=28, targetSdkVersion>=26, buildToolsVersion recommended 28.0.3
classpath 'com.android.tools.build:gradle:3.6.3'
It should be noted that the Gradle configuration here is
The configuration of gradle plugin needs to correspond to
gradle version:
The development environment configuration is as follows:
android {
compileSdkVersion 29
buildToolsVersion "30.0.2"
useLibrary 'org.apache.http.legacy'
defaultConfig {
applicationId "com.cszs.jgdnc.mi"
minSdkVersion 24
targetSdkVersion 28
versionCode 1
versionName "2.0"
}
sourceSets.main{
jniLibs.srcDir 'libs'
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
compileOptions {
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_1_8
}
}
First access the sdk of the online game:
(1) Introduce files in the res and lib folders
* Create an application on Xiaomi Developer and obtain the AppId, AppKey and AppSecret (note that AppSecret is used for server-side signature, do not use it on the client). When creating an application, if it is a game, the PackageName must be suffixed with ".mi".
* Completely add the resources in the res directory in the SDK package to the res directory of the game Android project. If there are conflicts in styles, they can be modified as appropriate.
* Place the files in the libs directory of the SDK package in the libs directory of your project (the name of the mio_sdk_base_3.2.0_12748.jar package in the picture will change according to different versions. The actual name shall prevail. Some third-party packages It may also change due to different versions, whichever is actual), reference it in the buildpath, and then initialize the SDK (if x86 is not supported, do not copy the x86 directory and its contents, because armeabi-v7a is compatible with armeabi, armeabi-v7a or The so files under armeabi are actually the same, please put them in the directory of armeabi-v7a and/or armeabi architecture that your game actually supports).
Library file path:
New files in the arm64-v8a folder, armeabi-v7a file, and x86 folder:
Then add the folder:
Possible errors:
Solution: Add dependencies back
implementation 'com.android.support:appcompat-v7:22.1.1'
(2) Introduce the jar package body:
implementation files('libs/mio_sdk_base_3.2.8_12822.jar')
implementation files('libs/alipaySdk-20180601.jar')
implementation files('libs/eventbus-3.0.0.jar')
implementation files('libs/gaid.jar')
implementation files('libs/onetrack-sdk-1.1.3.jar')
implementation files('libs/org.apache.http.legacy.jar')
implementation files('libs/protobuf-java-2.6.1.jar')
implementation files('libs/zxing-3.1.0.jar')
(3) SDK initialization code:
Create MMApplication.java under the demo package and initialize Xiaomi sdk:
package demo;
import android.support.multidex.MultiDexApplication;
import android.util.Log;
//这些包要等小米的广告sdk包引入后再引入
import com.xiaomi.ad.mediation.internal.config.IMediationConfigInitListener;
import com.xiaomi.ad.mediation.mimonew.MIMOAdSdkConfig;
import com.xiaomi.ad.mediation.mimonew.MiMoNewSdk;
import com.cszs.jgdnc.mi.R; //这里包名要改
import com.xiaomi.gamecenter.sdk.MiCommplatform;
import com.xiaomi.gamecenter.sdk.MiErrorCode;
import com.xiaomi.gamecenter.sdk.OnInitProcessListener;
import com.xiaomi.gamecenter.sdk.OnLoginProcessListener;
import com.xiaomi.gamecenter.sdk.entry.MiAccountInfo;
import com.xiaomi.gamecenter.sdk.entry.MiAppInfo;
import java.util.List;
/**
* Copyright (C) 2013, Xiaomi Inc. All rights reserved.
*/
public class MMApplication extends MultiDexApplication {
private static final String TAG = "MMApplication";
private static MainActivity mActivity;
private static final String APPID = "2882303761520039686";
@Override
public void onCreate() {
super.onCreate();
//网游sdk初始化
MiAppInfo appInfo = new MiAppInfo();
//正式环境下的appid
appInfo.setAppId(APPID);
//测试广告包的appid
// appInfo.setAppId("2882303761517973922");
//正式包体的appKey
appInfo.setAppKey("5852003941686");
// appInfo.setAppKey("");
Log.d("initSDK", "initSDK");
MiCommplatform.Init(this, appInfo, new OnInitProcessListener() {
@Override
public void finishInitProcess(List<String> loginMethod, int gameConfig) {
Log.i("Demo","Init success");
}
@Override
public void onMiSplashEnd() {
//小米闪屏⻚结束回调,小米闪屏可配,无闪屏也会返回此回调,游戏的闪屏应当在收到此回调之后
}
});
}
}
Then declare this Application in AndroidManifest.xml:
These two lines of code are very important and cannot be left out! ! !
android:extractNativeLibs="true"
android:name="demo.MMApplication"
A problem may arise here:
Solution: It turns out that introducing the package is not enough;
Need to introduce dependencies
build.gradle file:
:
/**sdk**/
implementation 'com.github.bumptech.glide:glide:4.9.0'
annotationProcessor 'com.github.bumptech.glide:compiler:4.9.0'
implementation 'com.google.code.gson:gson:2.8.5'
implementation 'com.android.support:multidex:1.0.3'
(4) New permissions are required in AndroidManifest.xml:
<uses-permission android:name="com.xiaomi.permission.AUTH_SERVICE"/>
<uses-permission android:name="com.xiaomi.sdk.permission.PAYMENT" />
(5) If you run it directly at this time, an error will be reported, because
The activity configuration and resource files required for running are missing
: Please ensure that the following Activity is declared in AndroidManifest.xml: [com.xiaomi.gamecenter.sdk .ui.MiActivity, com.xiaomi.gamecenter.sdk.ui.PayListActivity, com.xiaomi.hy.dj.HyDjActivity, com.alipay.sdk.app.H5PayActivity, com.xiaomi.gamecenter.sdk.ui.notice.NoticeActivity , com.xiaomi.gamecenter.sdk.ui.fault.ViewFaultNoticeActivity, com.xiaomi.gamecenter.sdk.anti.ui.MiAntiAlertActivity, com.xiaomi.gamecenter.sdk.ui.MiPayAntiActivity, ]
Solution:
The AndroidManifest manifest configuration required by the SDK,
is configured in AndroidManifest.xml:
<!-- Xiaomi SDK Need -->
<meta-data
android:name="notch.config"
android:value="portrait|landscape" />
<activity
android:name="com.xiaomi.gamecenter.sdk.ui.MiActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
</activity>
<activity
android:name="com.xiaomi.gamecenter.sdk.ui.PayListActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
<activity
android:name="com.xiaomi.hy.dj.HyDjActivity"
android:configChanges="orientation|screenSize"
android:exported="true"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
<activity
android:name="com.alipay.sdk.app.H5PayActivity"
android:configChanges="orientation|keyboardHidden|navigation|screenSize"
android:exported="false"
android:screenOrientation="behind"
android:windowSoftInputMode="adjustResize|stateHidden" />
<!--不支持${applicationId}的请替换为包名-->
<provider
android:name="com.xiaomi.gamecenter.sdk.utils.MiFileProvider"
android:authorities="${applicationId}.mi_fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/mio_file_paths" />
</provider>
<activity
android:name="com.xiaomi.gamecenter.sdk.ui.fault.ViewFaultNoticeActivity"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
<activity
android:name="com.xiaomi.gamecenter.sdk.ui.notice.NoticeActivity"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
<activity
android:name="com.xiaomi.gamecenter.sdk.anti.ui.MiAntiAlertActivity"
android:configChanges="orientation|screenSize"
android:excludeFromRecents="true"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen">
<intent-filter>
<data
android:host="open_anti_alert"
android:scheme="mioauthsdk" />
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.VIEW" />
</intent-filter>
</activity>
<activity
android:name="com.xiaomi.gamecenter.sdk.ui.MiPayAntiActivity"
android:configChanges="orientation|screenSize"
android:screenOrientation="behind"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen" />
<activity android:name="com.xiaomi.gamecenter.sdk.ui.MiVerifyActivity"
android:configChanges="orientation|screenSize"
android:theme="@android:style/Theme.Light.NoTitleBar.Fullscreen"
android:screenOrientation="behind"/>
<!-- Xiaomi SDK Need End-->
After configuring AndroidManifest.xml, since these activities rely on many xml files for layout, all dependent xml files must be copied to the corresponding folders. There are many files, and none of them can be missing. They are all dependent on each other, which is very difficult. trouble:
also,
Introducing this xml layout file is not enough. You need to introduce the dependencies of these xml layout files into the build.gradle file:
/**Introduce some dependencies required for xml layout**/
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:design:28.0.0'
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:1.3.31"
implementation 'com.jakewharton:butterknife:8.8.1'
annotationProcessor 'com.jakewharton:butterknife-compiler:8.8.1'
implementation 'android.arch.navigation:navigation-fragment:1.0.0'
implementation 'android.arch.navigation:navigation-ui:1.0.0'
implementation 'android.arch.lifecycle:extensions:1.1.1'
(6) If you run it directly at this time, an error will be reported because
The jsBridge-mix.js file is missing:
Caused by: java.lang.IllegalStateException: Please ensure that the file exists in the Assets directory: jsBridge-mix.js
Solution:
Add to here:
(7) I tried to package, but during the packaging process, an error was reported:
Solution: In the gradle.properties file, add:
android.enableBuildCache=false
(8) Call Xiaomi SDK login interface:
The login interface must be called every time you log in to the game: define the login interface in MMApplication.java:
public void initSDK(MainActivity _mActivity){
mActivity =_mActivity;
MiCommplatform.getInstance().miLogin(mActivity,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(int code , MiAccountInfo arg1)
{
switch( code )
{
case MiErrorCode.MI_XIAOMI_PAYMENT_SUCCESS:// 登陆成功
Log.i(TAG,"小米登录成功");
//获取用户的登陆后的UID(即用户唯一标识)
String uid = arg1.getUid();
//以下为获取session并校验流程,如果是网络游戏必须校验,(12小时过期)
//获取用户的登陆的Session(请参考5.3.3流程校验Session有效性)
String session = arg1.getSessionId();
//请开发者完成将uid和session提交给开发者自己服务器进行session验证
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_LOGIN_FAIL:
Log.i(TAG,"登录失败");
// 登陆失败
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_CANCEL:
Log.i(TAG,"取消登录");
// 取消登录
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_ACTION_EXECUTED:
//登录操作正在进行中
Log.i(TAG,"登录操作正在进行中");
break;
default:
// 登录失败
Log.i(TAG,"登录失败");
break;
}
}
} );
}
(9) Required interface, the game exit interface is defined in MainActivity.java:
public void exitGame(){
MiCommplatform.getInstance().miAppExit( this, new OnExitListner()
{
@Override
public void onExit( int code )
{
Log.i("Demo","小米游戏退出");
if ( code == MiErrorCode.MI_XIAOMI_EXIT )
{
android.os.Process.killProcess( android.os.Process.myPid() );
}
}
} );
}
3. Advertising sdk access:
(1) Introduce the aar package of advertising sdk:
The correct way to introduce the aar package is as follows
implementation files('libs/mimo_sdk.aar')
When using the wrong reference method, an error may occur: Could not resolve all files for configuration ':app:debugCompileClasspath'.
Solution: Place google() in front of jcenter()
buildscript {
repositories {
google()
jcenter()
mavenCentral()
maven { url 'https://maven.aliyun.com/repository/google'}
}
dependencies {
classpath 'com.android.tools.build:gradle:3.6.3'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
mavenCentral()
maven {url 'https://dl.bintray.com/jetbrains/anko'}
maven {url 'https://maven.aliyun.com/repository/google'}
}
}
If this still doesn’t work, try another reference method:
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
testImplementation 'junit:junit:4.12'
implementation 'com.android.support:appcompat-v7:22.1.1'
implementation 'com.android.support:support-v4:27.1.1'
implementation files('libs/mio_sdk_base_3.2.8_12822.jar')
implementation files('libs/alipaySdk-20180601.jar')
implementation files('libs/eventbus-3.0.0.jar')
implementation files('libs/gaid.jar')
implementation files('libs/onetrack-sdk-1.1.3.jar')
implementation files('libs/org.apache.http.legacy.jar')
implementation files('libs/protobuf-java-2.6.1.jar')
implementation files('libs/zxing-3.1.0.jar')
implementation files('libs/mimo_sdk.aar')
}
(2) Advertising sdk initialization:
Initialized in MMapplication.java: Here the advertising sdk initialization and calling the login interface are placed in the initSDK function:
Because the SDK initialization interface must be called after the user chooses whether to unify the privacy agreement, if the user rejects the privacy agreement, the advertising SDK initialization interface cannot be called, so
must be called after calling android privacy In the policy pop-up window, click Agree before calling the initSDK function here
The appid here is the test id during the test, and the advertising sdk needs to be set to test mode:
Otherwise, an error message for loading ads will appear: -400
public void initSDK(MainActivity _mActivity){
mActivity =_mActivity;
//广告sdk初始化
Log.i(TAG,"广告sdk初始化");
MiMoNewSdk.init(this, APPID, getString(R.string.app_name),
new MIMOAdSdkConfig.Builder()
.setDebug(false)
.setStaging(false).build(), new IMediationConfigInitListener() {
@Override
public void onSuccess() {
Log.i(TAG,"广告sdk初始化成功");
}
@Override
public void onFailed(int errorCode) {
Log.i(TAG,"广告sdk初始化失败"+errorCode);
}
});
MiCommplatform.getInstance().miLogin(mActivity,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(int code , MiAccountInfo arg1)
{
switch( code )
{
case MiErrorCode.MI_XIAOMI_PAYMENT_SUCCESS:// 登陆成功
Log.i(TAG,"小米登录成功");
//获取用户的登陆后的UID(即用户唯一标识)
String uid = arg1.getUid();
//以下为获取session并校验流程,如果是网络游戏必须校验,(12小时过期)
//获取用户的登陆的Session(请参考5.3.3流程校验Session有效性)
String session = arg1.getSessionId();
//请开发者完成将uid和session提交给开发者自己服务器进行session验证
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_LOGIN_FAIL:
Log.i(TAG,"登录失败");
// 登陆失败
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_CANCEL:
Log.i(TAG,"取消登录");
// 取消登录
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_ACTION_EXECUTED:
//登录操作正在进行中
Log.i(TAG,"登录操作正在进行中");
break;
default:
// 登录失败
Log.i(TAG,"登录失败");
break;
}
}
} );
}
When developers access the SDK, the application package may not have been put on the app store. When accessing, it is recommended to use the test advertising space in the demo for debugging, and then switch to the official environment and replace it with the official environment after ensuring that there are no problems with the access method. Advertising slot id. The APP_ID used in the test is: 2882303761517973922
advertisement type
|
Test ad slot ID
|
Width
|
28e12557924f47bcde1fb4122527a6bc
|
Horizontal interstitial advertising
|
dc7cc080d643693f4f835b1a7718283d
|
Vertical interstitial advertising
|
a61183c0f3899bc138a320925df3d862
|
Horizontal full screen interstitial advertising
|
756c0d2cdb935266522249c90ca04dbe
|
Vertical full-screen interstitial advertising
|
b539ee9934e2e869c6aced477a02fa0e
|
Horizontal rewarded video ads
|
feff23d4d67802626433de32bd1b327d
|
Vertical rewarded video ads
|
95297e164e1dfb6c0ce4a2eaf61cc791
|
Open the screen horizontally
|
f22820b630d6d453f956cbe31235d11a
|
Native template - picture above and below (with title)
|
bfa05071958648861ef32be94c4ac200
|
Native template - text on the left and image on the right (with title)
|
77c1a503091c597f8a03d57010637d7c
|
Native template - picture on the left and text on the right (version A with title)
|
8db571afaf731ec727d42db9894d688d
|
Native template - picture on the left and text on the right (version B with title)
|
5d1bab599fc4443c17021ea75dfa729d
|
Native template - picture above and below (large picture)
|
671f83d6d6c1f2356c1a14de9f7ec9cf
|
Native template - picture above and below (group picture)
|
b72a783f1f1952c09e429f777cf2426e
|
Self-rendering - big picture of information flow
|
c09e2a394366b0819fd3ac2bc142ed20
|
Self-rendering - information flow thumbnail
|
11cc7b67acfc800ac6228af78f122acf
|
Self-rendering - information flow diagram
|
949f4411ceceb8d14042dffb1112af6b
|
(3) Modification
provider statement required by SDK:
Add the file file_paths.xml under res/xml/ for reference demo
content:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path name="tt_internal_file_download" path="Download" />
<cache-path name="tt_internal_cache_download" path="Download" />
</paths>
**/
/**
在 res/xml/下添加文件 mimo_file_paths.xml 参考demo
内容:
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="mimoDownload" name="files_root" />
<external-path path="." name="external_storage_root" />
</paths>
**/
AndroidMainfest.xml新增provider声明:
<!-- 广告sdk需要的-->
<provider
android:name="com.bytedance.sdk.openadsdk.TTFileProvider"
android:authorities="${applicationId}.TTFileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
<provider
android:name="com.bytedance.sdk.openadsdk.multipro.TTMultiProvider"
android:authorities="${applicationId}.TTMultiProvider"
android:exported="false" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/mimo_file_paths" />
</provider>
4.Banner access:
Xiaomi's banner advertisement requires creating a ViewGround in the android project and rendering it inside. The specific steps are:
(1)
Create a new activity_main.xml file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
tools:ignore="HardcodedText"
android:layout_width="match_parent"
android:layout_height="match_parent">
<!-- BannerView的Container -->
<FrameLayout
android:id="@+id/game_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#D5D5D5" />
<FrameLayout
android:id="@+id/banner_container"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="#D5D5D5"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
(2)
Reset ContentView in MainActivity’s initEngin:
//声明变量先:
private ViewGroup gameContainer;
public ViewGroup banner_container;
public void initEngine()
{
mProxy = new RuntimeProxy(this);
mPlugin = new GameEngine(this);
mPlugin.game_plugin_set_runtime_proxy(mProxy);
mPlugin.game_plugin_set_option("localize","false");
mPlugin.game_plugin_set_option("gameUrl", App_Startup_Entry);
mPlugin.game_plugin_init(3);
View gameView = mPlugin.game_plugin_get_view();
this.setContentView(R.layout.activity_main);
this.gameContainer = findViewById(R.id.game_container);
this.banner_container = findViewById(R.id.banner_container);
this.gameContainer.addView(gameView);
mProxy.InitAD();
isLoad=true;
}
(3) The interface getApplication(), which is needed to create a banner, needs to call the MMApplication.java created before:
5. Review rejection: Automated test rejection, for Android 9 and 10 machines, reason: Failed to install /tmp/.omni/apks/0915153229_null_0255928c3835f474ea0a7fffe9f5b9b4b83f8ac40.apk: Failure [INSTALL_FAILED_INVALID_APK: Failed to extract native libraries, res=-2]
Solution:
Open AndroidManifest.xml
Add in the application node:
android:extractNativeLibs="true"
6. Review and rejection:
Solve the problem:
(1) Hide status bar and virtual keys:
[Tencent Documentation] How to hide the status bar and virtual keys
How to hide the status bar and virtual keys
. Test model: MI11 MIUI12.5 stable version
View decorView = getWindow().getDecorView();
int visibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE
| View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_FULLSCREEN //Hide the status bar
| View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //Hide virtual keys
| View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY;
decorView.setSystemUiVisibility(visibility);
//On versions greater than android P, you need to set flag: LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES to ensure that the application can display the notch area.
//If this flag is set, on notch screen phones, pay attention to the position of the internal controls of the application, which should be kept at a certain distance from the edge of the screen to prevent occlusion.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
getWindow().getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
}
(2) Set the app to full screen:
<style name="Theme.AppCompat.NoActionBar">
<item name="windowActionBar">false</item>
<item name="windowNoTitle">true</item>
</style>
7. Review and rejection issues:
8. Problem that the close button is not displayed after it is defined in the xml file: Solution:
(1)
RelativeLayout
or FrameLayout layout, if you do not set the position and fill the entire layout view later, it will be covered, check it yourself!
(2) Modify the xml attribute in ImageView:
<ImageView
android:id="@+id/view_ad_close"
android:layout_width="35dp"
android:layout_height="35dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="40dp"
android:layout_marginBottom="16dp"
android:contentDescription="Close button"
android:src="@drawable/float_hide_tip_sel"
app:layout_constraintBottom_toTopOf="@+id/view_desc"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/view_title"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0" />
(3) It has nothing to do with whether the picture is in jpg or png format! !
9. Audit failure problem: the real-name authentication pop-up window is closed
Solution:
(1) In the call to agree to the privacy agreement, pass in the callback: JSBridge.java
//Called after the user agrees to the privacy agreement
public static void onUserAgreed(String json) {
Log.e("1111111", "User agrees to privacy policy");
try {
JSONObject jsonObj = new JSONObject(json);
((MainActivity) JSBridge.mMainActivity).onUserAgreed(jsonObj, new ValueCallback<JSONObject>() {
@Override
public void onReceiveValue(JSONObject value) {
ExportJavaFunction.CallBackToJS(JSBridge.class, "onUserAgreed", value.toString());
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
Called in MainActivity.java: Only when the login is successful will a result=1 in the js layer be called back, otherwise the game will be exited;
public void onUserAgreed(JSONObject jsonObj, final ValueCallback<JSONObject> callback){
Log.d("UserAgreed", "Login info = " + jsonObj.toString());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
/**
* 如果你的targetSDKVersion >= 23,就要主动申请好权限。如果您的App没有适配到Android6.0(即targetSDKVersion < 23),那么只需要在这里直接调用fetchSplashAd方法。
*
*/
checkAndRequestPermissions();
} else {
/**
* 如果是Android6.0以下的机器,默认在安装时获得了所有权限,可以直接调用SDK。
*/
}
MiCommplatform.getInstance().onUserAgreed(this);
MiCommplatform.getInstance().miLogin(this,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(int code , MiAccountInfo arg1)
{
switch( code )
{
case MiErrorCode.MI_XIAOMI_PAYMENT_SUCCESS:// 登陆成功
Log.i("Demo","小米登录成功");
//获取用户的登陆后的UID(即用户唯一标识)
String uid = arg1.getUid();
//以下为获取session并校验流程,如果是网络游戏必须校验,(12小时过期)
//获取用户的登陆的Session(请参考5.3.3流程校验Session有效性)
String session = arg1.getSessionId();
//请开发者完成将uid和session提交给开发者自己服务器进行session验证
Log.e("UserAgreed", "登陆成功");
JSONObject result3 = new JSONObject();
try {
result3.put("result", 1);
} catch (JSONException e) {
e.printStackTrace();
}
callback.onReceiveValue(result3);
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_LOGIN_FAIL:
loginFail(callback);
// 登陆失败
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_CANCEL:
loginFail(callback);
// 取消登录
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_ACTION_EXECUTED:
//登录操作正在进行中
break;
default:
// 登录失败
loginFail(callback);
break;
}
}
} );
}
Login failed callback:
public void loginFail(final ValueCallback<JSONObject> callback){
Log.e("UserAgreed", "登陆失败");
JSONObject result = new JSONObject();
try {
result.put("result", 0);
} catch (JSONException e) {
e.printStackTrace();
}
callback.onReceiveValue(result);
}
(2)退出游戏:
MainActivity.java:
public void exitGame(){
MiCommplatform.getInstance().miAppExit( this, new OnExitListner()
{
@Override
public void onExit( int code )
{
Log.i("Demo","小米游戏退出");
if ( code == MiErrorCode.MI_XIAOMI_EXIT )
{
android.os.Process.killProcess( android.os.Process.myPid() );
}
}
} );
}
JSBridge.java:
//exit the game
public static void ExitGame(){
((MainActivity) JSBridge.mMainActivity).exitGame();
}
The functions at the js level are as follows:
static onUserAgreed(thisAry, callback) {
if (!this.isReady) {
callback({ result: 1 });
return;
}
let obj = {};
this.bridge.callWithBack((value) => {
console.log("JS layer login callback", value)
console.log(value)
if (callback) {
let jsonObj = JSON.parse(value);
callback.call(thisAry, jsonObj);
}
}, 'onUserAgreed', JSON.stringify(obj));
}
static ExitGame() {
console.log("Exit game");
if (!this.isReady)
return;
this.bridge.callWithBack(null, 'ExitGame');
}
10. Ad loading error: This error is that the ad type selected in the background does not match the ad type actually requested and has been filtered.
Template ad loading error {errorCode=-300, externalErrorCode='301007', errorMessage=''}
11. Permission issue: Advertising SDK should not be initialized before using it to agree to the terms of the privacy policy
Solution: Only call login and advertising sdk initialization after agreeing to the privacy policy:
In MainActivity.java:
public void onUserAgreed(JSONObject jsonObj, final ValueCallback<JSONObject> callback){
Log.d("UserAgreed", "Login info = " + jsonObj.toString());
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1) {
/**
* 如果你的targetSDKVersion >= 23,就要主动申请好权限。如果您的App没有适配到Android6.0(即targetSDKVersion < 23),那么只需要在这里直接调用fetchSplashAd方法。
*
*/
checkAndRequestPermissions();
} else {
/**
* 如果是Android6.0以下的机器,默认在安装时获得了所有权限,可以直接调用SDK。
*/
}
MiCommplatform.getInstance().onUserAgreed(this);
MMApplication mApplication = (MMApplication) getApplication();
mApplication.initSDK(callback,this);
}
MMApplication.java中,但是联运SDK的初始化,还是应该在onCreate函数中调用才行,不然会无法运行apk
public void initSDK(final ValueCallback<JSONObject> callback, MainActivity _mActivity){
mActivity =_mActivity;
MiCommplatform.getInstance().miLogin(mActivity,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(int code , MiAccountInfo arg1)
{
switch( code )
{
case MiErrorCode.MI_XIAOMI_PAYMENT_SUCCESS:// 登陆成功
Log.i("Demo","小米登录成功");
//获取用户的登陆后的UID(即用户唯一标识)
String uid = arg1.getUid();
//以下为获取session并校验流程,如果是网络游戏必须校验,(12小时过期)
//获取用户的登陆的Session(请参考5.3.3流程校验Session有效性)
String session = arg1.getSessionId();
//请开发者完成将uid和session提交给开发者自己服务器进行session验证
Log.e("UserAgreed", "登陆成功");
JSONObject result3 = new JSONObject();
try {
result3.put("result", 1);
} catch (JSONException e) {
e.printStackTrace();
}
callback.onReceiveValue(result3);
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_LOGIN_FAIL:
mActivity.loginFail(callback);
// 登陆失败
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_CANCEL:
mActivity.loginFail(callback);
// 取消登录
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_ACTION_EXECUTED:
//登录操作正在进行中
break;
default:
// 登录失败
mActivity.loginFail(callback);
break;
}
}
} );
//广告sdk初始化
MiMoNewSdk.init(this, APPID, getString(R.string.app_name),
new MIMOAdSdkConfig.Builder()
.setDebug(false)
.setStaging(false).build(), new IMediationConfigInitListener() {
@Override
public void onSuccess() {
MLog.d(TAG, "mediation config init success");
mActivity.mProxy.InitAD();
}
@Override
public void onFailed(int errorCode) {
MLog.d(TAG, "mediation config init failed");
}
});
}
12. The tentative game timeline in Xiaomi apk can be used:
if(Laya.timer.scale == 1)Laya.timer.pause();
if(Laya.timer.scale == 0)Laya.timer.resume()
13. Access and open the webpage in Xiaomi apk:
(1) Define VIEW in xml:
<FrameLayout
android:id="@+id/view_url_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="0dp"
android:layout_marginTop="0dp"
android:layout_marginRight="0dp"
android:layout_marginBottom="0dp"
android:background="#FFFFFF">
<WebView
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:id="@+id/wv"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:layout_alignParentTop="true" />
<ImageView
android:id="@+id/view_url_close"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_marginStart="9dp"
android:layout_marginTop="20dp"
android:layout_marginEnd="400dp"
android:contentDescription="关闭按钮"
android:src="@drawable/float_hide_tip_sel"
app:layout_constraintBottom_toTopOf="@+id/view_feedBox_image"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.78"
app:layout_constraintStart_toEndOf="@+id/view_feedBox_image"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
(2) Define the class that opens the View:
public class SecretUrlView {
private MainActivity mActivity;
private static String TAG = "SecretUrlView";
private View mView;
private WebView wv;
public SecretUrlView(MainActivity mActivity) {
this.mActivity = mActivity;
this.init();
}
public void init(){
mView = (ViewGroup) mActivity.urlView_container;
wv=(WebView)mView.findViewById(R.id.wv);
WebSettings ws=wv.getSettings();
ws.setJavaScriptEnabled(true);
wv.loadUrl("https://res.wqop2018.com//app/common/privacy.html");
wv.setWebViewClient(new WebViewClient());
mView.findViewById(R.id.view_url_close).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mView.setVisibility(View.GONE);
}
});
mView.setVisibility(View.GONE);
}
public void showUrlView(){
mView.setVisibility(View.VISIBLE);
}
public void hideUrlView(){
mView.setVisibility(View.GONE);
}
}
14. Solutions to privacy issues:
(1) Open the game > Pop up the privacy agreement (initialize Xiaomi sdk) > Agree to the privacy agreement > Obtain mobile phone information authorization > Initialize Xiaomi advertising sdk (Xiaomi login) > Log in successfully > Game loading starts
If login fails, you need to continue calling the login interface.
(2) TD initialization needs to be placed after the user agrees to the privacy agreement and agrees to grant permissions
(3) Privacy agreement address:
Privacy Policy
"https://res.wqop2018.com/app/web/privacy/v3/privacy.html?app_name=" + Constant.APP_NAME + "&company="+Constant.COMPANY+"&package_name="+Constant.PACKAGE_NAME
15. This does not solve the problem: It is found that obtaining mobile phone information is done when the Laya engine is initialized, so it is necessary to use Android to make a privacy interface, and then initialize the Laya engine after agreeing to privacy:
Read IMEI
发生时间 2021-11-23 10:07:42 md5=5743438D7E55887D2CFA5AFEE84D9F6B,pkg=com.cszs.aycsmnq.mi,action=android.permission.READ_PHONE_STATE_IMEI,content=,callstack:android.telephony.TelephonyManager.getDeviceId:1247;layaair.game.device.DevID.GetIMEI:14;layaair.game.browser.ExportJavaFunction.GetDeviceInfo:28;java.lang.reflect.Method.invoke:-2;layaair.game.browser.ExportJavaFunction.callMethod:43;layaair.game.browser.ConchJNI.OnGLReady:-2;layaair.game.browser.c.a:125;layaair.game.browser.x.i:384;layaair.game.browser.x.run:22;
Read IMSI
发生时间 2021-11-23 10:07:42 md5=5743438D7E55887D2CFA5AFEE84D9F6B,pkg=com.cszs.aycsmnq.mi,action=android.permission.READ_PHONE_STATE_IMSI,content=,callstack:android.telephony.TelephonyManager.getSubscriberId:3030;android.telephony.TelephonyManager.getSubscriberId:3011;layaair.game.device.DevID.GetIMSI:13;layaair.game.browser.ExportJavaFunction.GetDeviceInfo:40;java.lang.reflect.Method.invoke:-2;layaair.game.browser.ExportJavaFunction.callMethod:43;layaair.game.browser.ConchJNI.OnGLReady:-2;layaair.game.browser.c.a:125;layaair.game.browser.x.i:384;layaair.game.browser.x.run:22;
Get MAC address
发生时间 2021-11-23 10:07:42 md5=5743438D7E55887D2CFA5AFEE84D9F6B,pkg=com.cszs.aycsmnq.mi,action=android.permission.GET_MAC,content=wlan0:64:A2:F9:9C:72:1E,callstack:java.net.NetworkInterface.getHardwareAddress:574;layaair.game.device.DevID.getMac:61;layaair.game.device.DevID.GetWifiMac:0;layaair.game.browser.ExportJavaFunction.GetDeviceInfo:95;java.lang.reflect.Method.invoke:-2;layaair.game.browser.ExportJavaFunction.callMethod:43;layaair.game.browser.ConchJNI.OnGLReady:-2;layaair.game.browser.c.a:125;layaair.game.browser.x.i:384;layaair.game.browser.x.run:22;
Read personal information without permission: Read IMEI Read IMSI Get MAC address
16. Occasionally, interstitial advertising errors are reported. It seems that the timing is wrong, and the interstitial advertising is displayed before the advertising sdk is initialized:
java.lang.NullPointerException: Attempt to invoke virtual method 'void demo.ui.fullscreenInterstitialad.InterstitialView.showFullScreenAd(android.webkit.ValueCallback)' on a null object reference
17. Xiaomi must log in to load and enter the game:
(1) Process: After agreeing to the privacy policy in Android, initEngine, then log in on laya's loading page. If the login is successful, call back to laya, and then enter the game home page.
JS layer:
//Xiaomi must log in first
if (window.zs && zs.Native && zs.Native.Login) zs.Native.Login(this, this.apkLoginBack$.bind(this));
/**
* * Xiaomi login callback
*/
apkLoginBack$(data) {
console.log(data);
if (data.result == 1) {
this.loadingComplete$();
}
}
apk.mi.js:
static Login(thisAry, callback) {
if (!this.isReady)
return;
let obj = {};
obj['uid'] = "uid";
this.bridge.callWithBack((value) => {
if (callback) {
let jsonObj = JSON.parse(value);
callback.call(thisAry, jsonObj);
}
}, 'Login', JSON.stringify(obj));
}
(2) Android project in progress:
******JSBridge.java
public static void Login(String json){
try {
JSONObject jsonObj = new JSONObject(json);
MainActivity.mProxy.loginMi(jsonObj, new ValueCallback<JSONObject>() {
@Override
public void onReceiveValue(JSONObject value) {
ExportJavaFunction.CallBackToJS(JSBridge.class, "Login", value.toString());
}
});
} catch (JSONException e) {
e.printStackTrace();
}
}
******RuntimeProxy.java:
@Override
public void loginMi(JSONObject jsonObj, final ValueCallback<JSONObject> callback) {
Log.d(TAG, "loginMi " + jsonObj.toString());
if (hasNecessaryPMSGranted()) {
new Thread(new Runnable() {
@Override
public void run() {
mActivity.runOnUiThread(new Runnable() {
@Override
public void run() {
mActivity.loginMi(callback);
}
});
}
}).start();
} else {
Toast.makeText(mActivity, "Without READ_PHONE_STATE or WRITE_EXTERNAL_STORAGE permissions, the SDK cannot run properly!!!", Toast.LENGTH_SHORT).show();
}
}
******MainActivity.java:
public void loginMi(ValueCallback<JSONObject> callback_){
MMApplication mApplication = (MMApplication) getApplication();
mApplication.loginMI(callback_);
}
******MMApplication.java:
public void loginMI(ValueCallback<JSONObject> callback_){
if(loginSuccess)return;
callback = callback_;
Log.i(TAG,"Xiaomi login....");
MiCommplatform.getInstance().miLogin(mActivity,
new OnLoginProcessListener()
{
@Override
public void finishLoginProcess(int code , MiAccountInfo arg1)
{
switch( code )
{
case MiErrorCode.MI_XIAOMI_PAYMENT_SUCCESS:// Login successful
Log.i(TAG,"Xiaomi login successful");
//Get the user's UID after login (that is, the user's unique identifier)
String uid = arg1.getUid();
// The following is the process of obtaining the session and checking the process. If it is an online game, it must be verified, (12 hours expires)
//Get the user’s login Session (please refer to 5.3.3 process to verify Session validity)
String session = arg1.getSessionId();
// Please developers to complete the submission of UID and Session to the developer's own server for session verification
loginSuccess = true;
JSONObject result = new JSONObject();
try {
result.put("result", 1);
} catch (JSONException e) {
e.printStackTrace();
}
callback.onReceiveValue(result);
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_LOGIN_FAIL:
Log.i(TAG,"Login failed 22");
loginMI(callback_);
// Login failed
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_CANCEL:
Log.i(TAG,"Cancel Login");
loginMI(callback_);
break;
case MiErrorCode.MI_XIAOMI_PAYMENT_ERROR_ACTION_EXECUTED:
Log.i(TAG,"Login operation in progress 333");
break;
default:
// Login failed
Log.i(TAG,"Login failed");
break;
}
}
} );
}
18. Advertising loading error reporting:
Self-rendering ad loading error {errorCode=-400, externalErrorCode='', errorMessage='adPositionInfo is null'}
Usually you need to enable debugging:
MiMoNewSdk.init(this, "2882303761517973922", getString(R.string.app_name),
new MIMOAdSdkConfig.Builder()
.setDebug(true) // true turns on debugging and outputs debugging logs; false turns off debugging
.setStaging(true).build(), new IMediationConfigInitListener() { // true turns on the test request switch and requests test advertising; false turns off the test request switch
@Override
public void onSuccess() {
Log.i(TAG,"Advertising sdk initialization successful");
}
@Override
public void onFailed(int errorCode) {
Log.i(TAG,"Advertising sdk initialization failed"+errorCode);
}
});