Android Split Install Error(-2): Module_Unavailable Error

2.6k Views Asked by At

I am trying to implement on demand delivery feature in my android app. Now I am working on examples to understand how it works but when I try to install a dynamic module it shows an error message "Split Install Error(-2): A requested module is not available (to this user/device, for the installed apk). (https://developer.android.com/reference/com/google/android/play/core/splitinstall/model/SplitInstallErrorCode.html#MODULE_UNAVAILABLE)"

I have seen many examples and also followed google's split install documentation, and I have also seen many StackOverflow Question/Answers but I can't find any solution.

My code

MainActivity.java(Base App):

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(Base App):

<?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(Base App):

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(Dynamic Feature):

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(Dynamic Feature):

<?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(Dynamic Feature):

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

I have Edited the run configuration to "Apk from app bundle" and I am testing the app via Internal Testing Track but it is not working.

1

There are 1 best solutions below

0
On

Go to Run > Edit configurations and select Default APK, or make sure all your modules are checked as in the picture.

enter image description here