Skip to content

Commit

Permalink
Read loading unit mapping from AndroidManifest instead of strings (#2…
Browse files Browse the repository at this point in the history
  • Loading branch information
GaryQian committed Jan 24, 2021
1 parent a5c305e commit 4e87f60
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 12 deletions.
Expand Up @@ -6,9 +6,12 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.os.Build;
import android.os.Bundle;
import android.util.SparseArray;
import android.util.SparseIntArray;
import androidx.annotation.NonNull;
Expand Down Expand Up @@ -53,6 +56,8 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
private @NonNull SparseArray<String> sessionIdToState;
private @NonNull Map<String, Integer> nameToSessionId;

protected @NonNull SparseArray<String> loadingUnitIdToModuleNames;

private FeatureInstallStateUpdatedListener listener;

private class FeatureInstallStateUpdatedListener implements SplitInstallStateUpdatedListener {
Expand Down Expand Up @@ -202,6 +207,9 @@ public PlayStoreDeferredComponentManager(
sessionIdToLoadingUnitId = new SparseIntArray();
sessionIdToState = new SparseArray<>();
nameToSessionId = new HashMap<>();

loadingUnitIdToModuleNames = new SparseArray<>();
initLoadingUnitMappingToModuleNames();
}

public void setJNI(@NonNull FlutterJNI flutterJNI) {
Expand All @@ -222,19 +230,49 @@ public void setDeferredComponentChannel(DeferredComponentChannel channel) {
this.channel = channel;
}

private String loadingUnitIdToModuleName(int loadingUnitId) {
// Loading unit id to module name mapping stored in android Strings
// resources.
int moduleNameIdentifier =
context
.getResources()
.getIdentifier("loadingUnit" + loadingUnitId, "string", context.getPackageName());
return context.getResources().getString(moduleNameIdentifier);
@NonNull
private ApplicationInfo getApplicationInfo() {
try {
return context
.getPackageManager()
.getApplicationInfo(context.getPackageName(), PackageManager.GET_META_DATA);
} catch (NameNotFoundException e) {
throw new RuntimeException(e);
}
}

// Obtain and parses the metadata string. An example encoded string is:
//
// "2:module2,3:module3,4:module1"
//
// Where loading unit 2 is included in module2, loading unit 3 is
// included in module3, and loading unit 4 is included in module1.
private void initLoadingUnitMappingToModuleNames() {
String mappingKey = DeferredComponentManager.class.getName() + ".loadingUnitMapping";
ApplicationInfo applicationInfo = getApplicationInfo();
if (applicationInfo != null) {
Bundle metaData = applicationInfo.metaData;
if (metaData != null) {
String rawMappingString = metaData.getString(mappingKey, null);
if (rawMappingString == null) {
Log.e(
TAG,
"No loading unit to dynamic feature module name found. Ensure '"
+ mappingKey
+ "' is defined in the base module's AndroidManifest.");
} else {
for (String entry : rawMappingString.split(",")) {
String[] splitEntry = entry.split(":");
loadingUnitIdToModuleNames.put(Integer.parseInt(splitEntry[0]), splitEntry[1]);
}
}
}
}
}

public void installDeferredComponent(int loadingUnitId, String moduleName) {
String resolvedModuleName =
moduleName != null ? moduleName : loadingUnitIdToModuleName(loadingUnitId);
moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId);
if (resolvedModuleName == null) {
Log.e(
TAG,
Expand Down Expand Up @@ -297,7 +335,7 @@ public void installDeferredComponent(int loadingUnitId, String moduleName) {

public String getDeferredComponentInstallState(int loadingUnitId, String moduleName) {
String resolvedModuleName =
moduleName != null ? moduleName : loadingUnitIdToModuleName(loadingUnitId);
moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId);
if (resolvedModuleName == null) {
Log.e(
TAG,
Expand Down Expand Up @@ -400,7 +438,7 @@ public void loadDartLibrary(int loadingUnitId, String moduleName) {

public boolean uninstallDeferredComponent(int loadingUnitId, String moduleName) {
String resolvedModuleName =
moduleName != null ? moduleName : loadingUnitIdToModuleName(loadingUnitId);
moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId);
if (resolvedModuleName == null) {
Log.e(
TAG,
Expand All @@ -410,7 +448,9 @@ public boolean uninstallDeferredComponent(int loadingUnitId, String moduleName)
List<String> modulesToUninstall = new ArrayList<>();
modulesToUninstall.add(resolvedModuleName);
splitInstallManager.deferredUninstall(modulesToUninstall);
sessionIdToState.delete(nameToSessionId.get(resolvedModuleName));
if (nameToSessionId.get(resolvedModuleName) != null) {
sessionIdToState.delete(nameToSessionId.get(resolvedModuleName));
}
return true;
}

Expand Down
Expand Up @@ -5,6 +5,7 @@
package io.flutter.embedding.engine.deferredcomponents;

import static junit.framework.TestCase.assertEquals;
import static junit.framework.TestCase.assertFalse;
import static junit.framework.TestCase.assertTrue;
import static org.mockito.Mockito.any;
import static org.mockito.Mockito.anyInt;
Expand All @@ -19,6 +20,7 @@
import android.content.pm.PackageManager.NameNotFoundException;
import android.content.res.AssetManager;
import android.os.Bundle;
import android.util.SparseArray;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.loader.ApplicationInfoLoader;
Expand Down Expand Up @@ -70,6 +72,9 @@ public void deferredComponentInstallFailure(
private class TestPlayStoreDeferredComponentManager extends PlayStoreDeferredComponentManager {
public TestPlayStoreDeferredComponentManager(Context context, FlutterJNI jni) {
super(context, jni);
loadingUnitIdToModuleNames = new SparseArray<>();
loadingUnitIdToModuleNames.put(5, "FakeModuleName5");
loadingUnitIdToModuleNames.put(2, "FakeModuleName2");
}

@Override
Expand Down Expand Up @@ -223,4 +228,16 @@ public void stateGetterReturnsUnknowByDefault() throws NameNotFoundException {
new TestPlayStoreDeferredComponentManager(spyContext, jni);
assertEquals(playStoreManager.getDeferredComponentInstallState(-1, "invalidName"), "unknown");
}

@Test
public void loadingUnitMappingFindsMatch() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
TestPlayStoreDeferredComponentManager playStoreManager =
new TestPlayStoreDeferredComponentManager(spyContext, jni);

assertTrue(playStoreManager.uninstallDeferredComponent(5, null));
assertTrue(playStoreManager.uninstallDeferredComponent(2, null));
assertFalse(playStoreManager.uninstallDeferredComponent(3, null));
}
}

0 comments on commit 4e87f60

Please sign in to comment.