From 298310a37c0a0b75f16ee624d62447b09eb7ba62 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 11:42:36 -0800 Subject: [PATCH 01/11] Read loading unit mapping from AndroidManifest instead of strings --- .../PlayStoreDeferredComponentManager.java | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 22b25b34b3add..3ad1167862246 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -6,6 +6,8 @@ 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; @@ -53,6 +55,8 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag private @NonNull SparseArray sessionIdToState; private @NonNull Map nameToSessionId; + private @NonNull Map> loadingUnitIdToModuleNames; + private FeatureInstallStateUpdatedListener listener; private class FeatureInstallStateUpdatedListener implements SplitInstallStateUpdatedListener { @@ -202,6 +206,24 @@ public PlayStoreDeferredComponentManager( sessionIdToLoadingUnitId = new SparseIntArray(); sessionIdToState = new SparseArray<>(); nameToSessionId = new HashMap<>(); + + loadingUnitIdToModuleNames = new HashMap<>(); + String rawMappingString = getApplicationInfo().metaData + .getString("flutterDeferredComponentsLoadingUnitMapping", null); + if (rawMappingString == null) { + Log.e( + TAG, + "No loading unit to dynamic feature module name found. Ensure 'flutterDeferredComponentsLoadingUnitMapping' is defined in the base module's AndroidManifest."); + } else { + for (String entry : rawMappingString.split(",")) { + String[] splitEntry = entry.split(":"); + List moduleNames = new ArrayList<>(); + for (int i = 1; i < splitEntry.length; i++) { + moduleNames.add(splitEntry[i]); + } + loadingUnitIdToModuleNames.put(Integer.parseInt(splitEntry[0]), moduleNames); + } + } } public void setJNI(@NonNull FlutterJNI flutterJNI) { @@ -222,19 +244,20 @@ 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); + } } public void installDeferredComponent(int loadingUnitId, String moduleName) { String resolvedModuleName = - moduleName != null ? moduleName : loadingUnitIdToModuleName(loadingUnitId); + moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId).get(0); if (resolvedModuleName == null) { Log.e( TAG, @@ -297,7 +320,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).get(0); if (resolvedModuleName == null) { Log.e( TAG, @@ -400,7 +423,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).get(0); if (resolvedModuleName == null) { Log.e( TAG, From fce2de499ff9129f9b675d18789296e73b6669e6 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 11:58:09 -0800 Subject: [PATCH 02/11] Add tests --- .../PlayStoreDeferredComponentManager.java | 2 +- .../PlayStoreDeferredComponentManagerTest.java | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 3ad1167862246..56924b9428898 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -55,7 +55,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag private @NonNull SparseArray sessionIdToState; private @NonNull Map nameToSessionId; - private @NonNull Map> loadingUnitIdToModuleNames; + protected @NonNull Map> loadingUnitIdToModuleNames; private FeatureInstallStateUpdatedListener listener; diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index b5e98b27e5281..20ae14f058d4c 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -23,6 +23,7 @@ import io.flutter.embedding.engine.FlutterJNI; import io.flutter.embedding.engine.loader.ApplicationInfoLoader; import java.io.File; +import java.util.HashMap; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -70,6 +71,9 @@ public void deferredComponentInstallFailure( private class TestPlayStoreDeferredComponentManager extends PlayStoreDeferredComponentManager { public TestPlayStoreDeferredComponentManager(Context context, FlutterJNI jni) { super(context, jni); + loadingUnitIdToModuleNames = new HashMap<>(); + loadingUnitIdToModuleNames.put(5, "FakeModuleName5"); + loadingUnitIdToModuleNames.put(2, "FakeModuleName2"); } @Override @@ -223,4 +227,14 @@ public void stateGetterReturnsUnknowByDefault() throws NameNotFoundException { new TestPlayStoreDeferredComponentManager(spyContext, jni); assertEquals(playStoreManager.getDeferredComponentInstallState(-1, "invalidName"), "unknown"); } + + @Test + public void invalidSearchPathsAreIgnored() throws NameNotFoundException { + TestPlayStoreDeferredComponentManager playStoreManager = + new TestPlayStoreDeferredComponentManager(spyContext, jni); + + assertTrue(playStoreManager.uninstallDeferredComponent(5, null)); + assertTrue(playStoreManager.uninstallDeferredComponent(2, null)); + assertFalse(playStoreManager.uninstallDeferredComponent(3, null)); + } } From 2eed37c17f1b9d25ece34cee724ac20793242dc9 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 11:59:09 -0800 Subject: [PATCH 03/11] Import --- .../PlayStoreDeferredComponentManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index 20ae14f058d4c..f25617ca18ff6 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -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; From 4331b431d9ca754e4d34ed920e99bbd62928d618 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 12:03:48 -0800 Subject: [PATCH 04/11] Add docs --- .../PlayStoreDeferredComponentManager.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 56924b9428898..ef509f73237b2 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -207,7 +207,14 @@ public PlayStoreDeferredComponentManager( sessionIdToState = new SparseArray<>(); nameToSessionId = new HashMap<>(); + loadingUnitIdToModuleNames = new HashMap<>(); + // Parse the metadata string. An example encoded string is: + // + // "2:module1:module2,3:module3,4:module1" + // + // Where loading unit 2 is included in both module1 and module2, loading + // unit 3 is included in module3, and loading unit 4 is included in module1. String rawMappingString = getApplicationInfo().metaData .getString("flutterDeferredComponentsLoadingUnitMapping", null); if (rawMappingString == null) { From b953d74124941586522cee0d1a3f503932b426f0 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 13:14:18 -0800 Subject: [PATCH 05/11] Use class name as prefix --- .../PlayStoreDeferredComponentManager.java | 6 +++--- .../PlayStoreDeferredComponentManagerTest.java | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index ef509f73237b2..2c59fdab29f6f 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -207,7 +207,6 @@ public PlayStoreDeferredComponentManager( sessionIdToState = new SparseArray<>(); nameToSessionId = new HashMap<>(); - loadingUnitIdToModuleNames = new HashMap<>(); // Parse the metadata string. An example encoded string is: // @@ -215,12 +214,13 @@ public PlayStoreDeferredComponentManager( // // Where loading unit 2 is included in both module1 and module2, loading // unit 3 is included in module3, and loading unit 4 is included in module1. + String mappingKey = DeferredComponentManager.class.getName() + ".loadingUnitMapping"; String rawMappingString = getApplicationInfo().metaData - .getString("flutterDeferredComponentsLoadingUnitMapping", null); + .getString(mappingKey, null); if (rawMappingString == null) { Log.e( TAG, - "No loading unit to dynamic feature module name found. Ensure 'flutterDeferredComponentsLoadingUnitMapping' is defined in the base module's AndroidManifest."); + "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(":"); diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index f25617ca18ff6..4bace543d1071 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -230,7 +230,7 @@ public void stateGetterReturnsUnknowByDefault() throws NameNotFoundException { } @Test - public void invalidSearchPathsAreIgnored() throws NameNotFoundException { + public void loadingUnitMappingFindsMatch() throws NameNotFoundException { TestPlayStoreDeferredComponentManager playStoreManager = new TestPlayStoreDeferredComponentManager(spyContext, jni); From 0477899cffdcc5162a8b8748cdb02497cdbc6c36 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 13:34:00 -0800 Subject: [PATCH 06/11] Remove multiple modulenames per loading unit --- .../PlayStoreDeferredComponentManager.java | 27 +++++++++---------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 2c59fdab29f6f..1f422f494935a 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -55,7 +55,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag private @NonNull SparseArray sessionIdToState; private @NonNull Map nameToSessionId; - protected @NonNull Map> loadingUnitIdToModuleNames; + protected @NonNull Map loadingUnitIdToModuleNames; private FeatureInstallStateUpdatedListener listener; @@ -210,25 +210,22 @@ public PlayStoreDeferredComponentManager( loadingUnitIdToModuleNames = new HashMap<>(); // Parse the metadata string. An example encoded string is: // - // "2:module1:module2,3:module3,4:module1" + // "2:module2,3:module3,4:module1" // - // Where loading unit 2 is included in both module1 and module2, loading - // unit 3 is included in module3, and loading unit 4 is included in module1. + // Where loading unit 2 is included in module2, loading unit 3 is + // included in module3, and loading unit 4 is included in module1. String mappingKey = DeferredComponentManager.class.getName() + ".loadingUnitMapping"; - String rawMappingString = getApplicationInfo().metaData - .getString(mappingKey, null); + String rawMappingString = getApplicationInfo().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."); + "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(":"); - List moduleNames = new ArrayList<>(); - for (int i = 1; i < splitEntry.length; i++) { - moduleNames.add(splitEntry[i]); - } - loadingUnitIdToModuleNames.put(Integer.parseInt(splitEntry[0]), moduleNames); + loadingUnitIdToModuleNames.put(Integer.parseInt(splitEntry[0]), splitEntry[1]); } } } @@ -264,7 +261,7 @@ private ApplicationInfo getApplicationInfo() { public void installDeferredComponent(int loadingUnitId, String moduleName) { String resolvedModuleName = - moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId).get(0); + moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId); if (resolvedModuleName == null) { Log.e( TAG, @@ -327,7 +324,7 @@ public void installDeferredComponent(int loadingUnitId, String moduleName) { public String getDeferredComponentInstallState(int loadingUnitId, String moduleName) { String resolvedModuleName = - moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId).get(0); + moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId); if (resolvedModuleName == null) { Log.e( TAG, @@ -430,7 +427,7 @@ public void loadDartLibrary(int loadingUnitId, String moduleName) { public boolean uninstallDeferredComponent(int loadingUnitId, String moduleName) { String resolvedModuleName = - moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId).get(0); + moduleName != null ? moduleName : loadingUnitIdToModuleNames.get(loadingUnitId); if (resolvedModuleName == null) { Log.e( TAG, From af710ab9681f501205be88a089550d538cd382af Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 13:43:27 -0800 Subject: [PATCH 07/11] Use sparse array --- .../deferredcomponents/PlayStoreDeferredComponentManager.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 1f422f494935a..27b6409d3a6aa 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -55,7 +55,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag private @NonNull SparseArray sessionIdToState; private @NonNull Map nameToSessionId; - protected @NonNull Map loadingUnitIdToModuleNames; + protected @NonNull SparseArray loadingUnitIdToModuleNames; private FeatureInstallStateUpdatedListener listener; @@ -207,7 +207,7 @@ public PlayStoreDeferredComponentManager( sessionIdToState = new SparseArray<>(); nameToSessionId = new HashMap<>(); - loadingUnitIdToModuleNames = new HashMap<>(); + loadingUnitIdToModuleNames = new SparseArray<>(); // Parse the metadata string. An example encoded string is: // // "2:module2,3:module3,4:module1" From eae87b54eab71f5fdea127417b32b11f02116676 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 15:41:55 -0800 Subject: [PATCH 08/11] Fix tests --- .../PlayStoreDeferredComponentManagerTest.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index 4bace543d1071..a1cb543d4926a 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -231,6 +231,8 @@ public void stateGetterReturnsUnknowByDefault() throws NameNotFoundException { @Test public void loadingUnitMappingFindsMatch() throws NameNotFoundException { + TestFlutterJNI jni = new TestFlutterJNI(); + Context spyContext = spy(RuntimeEnvironment.application); TestPlayStoreDeferredComponentManager playStoreManager = new TestPlayStoreDeferredComponentManager(spyContext, jni); From 71e1df72ad415400c7847c8c27e8c8f4f99efe90 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 18:03:18 -0800 Subject: [PATCH 09/11] Fix test --- .../PlayStoreDeferredComponentManagerTest.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java index a1cb543d4926a..3157e9861f256 100644 --- a/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java +++ b/shell/platform/android/test/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManagerTest.java @@ -20,11 +20,11 @@ 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; import java.io.File; -import java.util.HashMap; import org.junit.Test; import org.junit.runner.RunWith; import org.robolectric.RobolectricTestRunner; @@ -72,7 +72,7 @@ public void deferredComponentInstallFailure( private class TestPlayStoreDeferredComponentManager extends PlayStoreDeferredComponentManager { public TestPlayStoreDeferredComponentManager(Context context, FlutterJNI jni) { super(context, jni); - loadingUnitIdToModuleNames = new HashMap<>(); + loadingUnitIdToModuleNames = new SparseArray<>(); loadingUnitIdToModuleNames.put(5, "FakeModuleName5"); loadingUnitIdToModuleNames.put(2, "FakeModuleName2"); } From 44203568670cc34f314f88d85d318f43f9a201f8 Mon Sep 17 00:00:00 2001 From: garyqian Date: Fri, 22 Jan 2021 19:06:04 -0800 Subject: [PATCH 10/11] refactor, improve null checking --- .../PlayStoreDeferredComponentManager.java | 51 +++++++++++-------- 1 file changed, 31 insertions(+), 20 deletions(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index 27b6409d3a6aa..bac6fe2fea298 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -11,6 +11,7 @@ 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; @@ -208,26 +209,7 @@ public PlayStoreDeferredComponentManager( nameToSessionId = new HashMap<>(); loadingUnitIdToModuleNames = new SparseArray<>(); - // Parse 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. - String mappingKey = DeferredComponentManager.class.getName() + ".loadingUnitMapping"; - String rawMappingString = getApplicationInfo().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]); - } - } + initLoadingUnitMappingToModuleNames(); } public void setJNI(@NonNull FlutterJNI flutterJNI) { @@ -259,6 +241,35 @@ private ApplicationInfo getApplicationInfo() { } } + // 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 : loadingUnitIdToModuleNames.get(loadingUnitId); From cb3db02fb111893617f190d0bab420fef46e7b57 Mon Sep 17 00:00:00 2001 From: garyqian Date: Sat, 23 Jan 2021 21:08:46 -0800 Subject: [PATCH 11/11] Check for null ids --- .../deferredcomponents/PlayStoreDeferredComponentManager.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java index bac6fe2fea298..829108651a0db 100644 --- a/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java +++ b/shell/platform/android/io/flutter/embedding/engine/deferredcomponents/PlayStoreDeferredComponentManager.java @@ -448,7 +448,9 @@ public boolean uninstallDeferredComponent(int loadingUnitId, String moduleName) List 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; }