Android 拆分安装错误 (-2):Module_Unavailable 错误

问题描述

我正在尝试在我的 android 应用中实现按需交付功能。现在我正在研究示例以了解它是如何工作的,但是当我尝试安装动态模块时,它显示一条错误消息“拆分安装错误(-2):请求的模块不可用(对于此用户/设备,对于已安装的apk)。(https://developer.android.com/reference/com/google/android/play/core/splitinstall/model/SplitInstallErrorCode.html#MODULE_UNAVAILABLE)"

我看过很多例子,也遵循了 google 的拆分安装文档,我也看过很多 StackOverflow 问题/答案,但我找不到任何解决方案。

我的代码

MainActivity.java(基础应用):

import androidx.appcompat.app.AppCompatActivity;


import android.os.Bundle;

import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;

import com.google.android.play.core.splitinstall.SplitInstallManager;
import com.google.android.play.core.splitinstall.SplitInstallManagerFactory;
import com.google.android.play.core.splitinstall.Splitinstallrequest;
import com.google.android.play.core.splitinstall.SplitInstallSessionState;
import com.google.android.play.core.splitinstall.SplitInstallStateUpdatedListener;
import com.google.android.play.core.splitinstall.model.SplitInstallSessionStatus;
import com.google.android.play.core.tasks.OnFailureListener;
import com.google.android.play.core.tasks.OnSuccessListener;

import java.io.File;


public class MainActivity extends AppCompatActivity {

private Button download;



private int mySessionId;

private static final String TAG = "MainActivity";

private SplitInstallManager splitInstallManager;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    download = findViewById(R.id.download);



    splitInstallManager = SplitInstallManagerFactory.create(getApplicationContext());

    download.setonClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            downloadDynamicModule();
        }
    });






}

private void downloadDynamicModule() {


    Splitinstallrequest request = Splitinstallrequest.newBuilder().addModule("dynamic").build();

    SplitInstallStateUpdatedListener listener = new SplitInstallStateUpdatedListener() {
        @Override
        public void onStateUpdate(SplitInstallSessionState splitInstallSessionState) {
            if(splitInstallSessionState.sessionId() == mySessionId) {
                switch (splitInstallSessionState.status()) {
                    case SplitInstallSessionStatus.DOWNLOADING:
                        Toast.makeText(MainActivity.this,"Dynamic Module downloading",Toast.LENGTH_SHORT).show();
                        // Update progress bar.
                        break;
                    case SplitInstallSessionStatus.INSTALLED:
                        Log.d(TAG,"Dynamic Module downloaded");
                        Toast.makeText(MainActivity.this,"Dynamic Module downloaded",Toast.LENGTH_SHORT).show();
                        break;
                }
            }
            else{
                Toast.makeText(MainActivity.this,"Session Not Created",Toast.LENGTH_SHORT).show();
            }
        }
    };

    splitInstallManager.registerListener(listener);

    splitInstallManager.startInstall(request).addOnFailureListener(new OnFailureListener() {
                @Override
                public void onFailure(Exception e) {
                    Toast.makeText(MainActivity.this,"Failed to Install "+e,Toast.LENGTH_SHORT).show();
                    Log.d(TAG,"ExceptionV: " + e);
                }
            })
            .addOnSuccessListener(new OnSuccessListener<Integer>() {
                @Override
                public void onSuccess(Integer sessionId) {
                    mySessionId = sessionId;
                    Toast.makeText(MainActivity.this,"Success"+sessionId,Toast.LENGTH_SHORT).show();
                }
            });
}
}

AndroidManifest(基础应用):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.package.dynamicfeaturemoduleexample">

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
    tools:ignore="ScopedStorage" />

<application
    android:allowBackup="true"

    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:roundIcon="@mipmap/ic_launcher_round"
    android:supportsRtl="true"
    android:theme="@style/Theme.DynamicFeatureModuleExample"
    android:name="com.google.android.play.core.splitcompat.SplitCompatApplication">
    <activity android:name=".MainActivity">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />

            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

</application>

Gradle(基础应用):

plugins {
id 'com.android.application'
}

android {
compileSdkVersion 29

defaultConfig {
    applicationId "com.package.dynamicfeaturemoduleexample"
    minSdkVersion 21
    targetSdkVersion 29
    versionCode 19
    versionName '2.9'

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}



buildTypes {
    release {
        minifyEnabled false
        proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'),'proguard-rules.pro'
    }
}


bundle {
    density {
        // Different APKs are generated for devices with different screen densities; true by default.
        enableSplit true
    }
    abi {
        // Different APKs are generated for devices with different cpu architectures; true by default.
        enableSplit true
    }
    language {
        // This is disabled so that the App Bundle does NOT split the APK for each language.
        // We're gonna use the same APK for all languages.
        enableSplit false
    }
}
dynamicFeatures = [':dynamic',':dynamicfeature',':newfeature']
}

dependencies {
implementation filetree(dir: 'libs',include: ['*.jar'])
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.3.0'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
implementation 'com.google.android.play:core:1.9.1'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

DynamicActivity.java(动态特征):

import android.app.Activity;

import android.os.Bundle;


public class DynamicActivity extends Activity {

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_dynamic_module);
}


}

AndoridManifest(动态特征):

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:dist="http://schemas.android.com/apk/distribution"
package="com.package.dynamic"
split="dynamic">

<dist:module
    dist:instant="false"
    dist:title="@string/title_dynamic">
    <dist:delivery>
        <dist:on-demand />
    </dist:delivery>
    <dist:fusing dist:include="true" />
</dist:module>

<application>
    <activity
        android:name="com.package.dynamic.DynamicActivity"
        android:label="@string/title_dynamic">
    </activity>
</application>
</manifest>

Gradle(动态特征):

apply plugin: 'com.android.dynamic-feature'

android {
compileSdkVersion 29

defaultConfig {
    applicationId "com.package.dynamic"
    minSdkVersion 21
    targetSdkVersion 29
    versionCode 16
    versionName '2.6'

    testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}

buildTypes {
    release {
        minifyEnabled false
        proguardFiles 'proguard-rules-dynamic-features.pro'
    }
}
}

dependencies {
implementation filetree(dir: 'libs',include: ['*.jar'])
implementation project(":app")
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
implementation 'com.google.android.play:core:1.9.1@aar'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
androidTestImplementation 'androidx.annotation:annotation:1.1.0'
}

My Google Play Developer Console App Bundle Reference

我已将运行配置编辑为“来自应用程序包的 Apk”,我正在通过内部测试跟踪测试应用程序,但它不起作用。

解决方法

转到 Run > Edit configurations 并选择 Default APK,或确保您的所有模块都如图所示进行了检查。

enter image description here

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...