mirror of
https://github.com/flutter/flutter.git
synced 2026-02-20 02:29:02 +08:00
Read loading unit mapping from AndroidManifest instead of strings (#23868)
This commit is contained in:
parent
a5c305e4e4
commit
4e87f60eaa
@ -6,9 +6,12 @@ package io.flutter.embedding.engine.deferredcomponents;
|
||||
|
||||
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;
|
||||
@ -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 {
|
||||
@ -202,6 +207,9 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
|
||||
sessionIdToLoadingUnitId = new SparseIntArray();
|
||||
sessionIdToState = new SparseArray<>();
|
||||
nameToSessionId = new HashMap<>();
|
||||
|
||||
loadingUnitIdToModuleNames = new SparseArray<>();
|
||||
initLoadingUnitMappingToModuleNames();
|
||||
}
|
||||
|
||||
public void setJNI(@NonNull FlutterJNI flutterJNI) {
|
||||
@ -222,19 +230,49 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
|
||||
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,
|
||||
@ -297,7 +335,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
|
||||
|
||||
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,
|
||||
@ -400,7 +438,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
|
||||
|
||||
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,
|
||||
@ -410,7 +448,9 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
@ -19,6 +20,7 @@ import android.content.pm.PackageManager;
|
||||
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;
|
||||
@ -70,6 +72,9 @@ public class PlayStoreDeferredComponentManagerTest {
|
||||
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
|
||||
@ -223,4 +228,16 @@ public class PlayStoreDeferredComponentManagerTest {
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user