未验证 提交 424ae67e 编写于 作者: L Lau Ching Jun 提交者: GitHub

Allow naming shared libraries in deferred component via AndroidManifest (#23925)

上级 4d51405c
......@@ -44,6 +44,9 @@ import java.util.Queue;
public class PlayStoreDeferredComponentManager implements DeferredComponentManager {
private static final String TAG = "PlayStoreDeferredComponentManager";
public static final String MAPPING_KEY =
DeferredComponentManager.class.getName() + ".loadingUnitMapping";
private @NonNull SplitInstallManager splitInstallManager;
private @Nullable FlutterJNI flutterJNI;
private @Nullable DeferredComponentChannel channel;
......@@ -57,6 +60,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
private @NonNull Map<String, Integer> nameToSessionId;
protected @NonNull SparseArray<String> loadingUnitIdToModuleNames;
protected @NonNull SparseArray<String> loadingUnitIdToSharedLibraryNames;
private FeatureInstallStateUpdatedListener listener;
......@@ -209,6 +213,7 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
nameToSessionId = new HashMap<>();
loadingUnitIdToModuleNames = new SparseArray<>();
loadingUnitIdToSharedLibraryNames = new SparseArray<>();
initLoadingUnitMappingToModuleNames();
}
......@@ -243,27 +248,33 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
// Obtain and parses the metadata string. An example encoded string is:
//
// "2:module2,3:module3,4:module1"
// "2:module2,3:module3,4:module1:libmodule4.so"
//
// Where loading unit 2 is included in module2, loading unit 3 is
// included in module3, and loading unit 4 is included in module1.
// An optional third parameter can be added to indicate the name of
// the shared library of the loading unit.
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);
String rawMappingString = metaData.getString(MAPPING_KEY, null);
if (rawMappingString == null) {
Log.e(
TAG,
"No loading unit to dynamic feature module name found. Ensure '"
+ mappingKey
+ MAPPING_KEY
+ "' 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]);
int loadingUnitId = Integer.parseInt(splitEntry[0]);
loadingUnitIdToModuleNames.put(loadingUnitId, splitEntry[1]);
if (splitEntry.length > 2) {
loadingUnitIdToSharedLibraryNames.put(loadingUnitId, splitEntry[2]);
}
}
}
}
......@@ -379,9 +390,12 @@ public class PlayStoreDeferredComponentManager implements DeferredComponentManag
return;
}
// This matches/depends on dart's loading unit naming convention, which we use unchanged.
String aotSharedLibraryName =
flutterApplicationInfo.aotSharedLibraryName + "-" + loadingUnitId + ".part.so";
String aotSharedLibraryName = loadingUnitIdToSharedLibraryNames.get(loadingUnitId);
if (aotSharedLibraryName == null) {
// If the filename is not specified, we use dart's loading unit naming convention.
aotSharedLibraryName =
flutterApplicationInfo.aotSharedLibraryName + "-" + loadingUnitId + ".part.so";
}
// Possible values: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64
String abi;
......
......@@ -20,7 +20,6 @@ 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;
......@@ -72,9 +71,6 @@ 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
......@@ -85,11 +81,25 @@ public class PlayStoreDeferredComponentManagerTest {
}
}
private Context createSpyContext(Bundle metadata) throws NameNotFoundException {
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
if (metadata == null) {
metadata = new Bundle();
}
PackageManager packageManager = mock(PackageManager.class);
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
applicationInfo.metaData = metadata;
when(packageManager.getApplicationInfo(any(String.class), any(int.class)))
.thenReturn(applicationInfo);
doReturn(packageManager).when(spyContext).getPackageManager();
return spyContext;
}
@Test
public void downloadCallsJNIFunctions() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
String soTestFilename = "libapp.so-123.part.so";
String soTestPath = "test/path/" + soTestFilename;
......@@ -114,19 +124,13 @@ public class PlayStoreDeferredComponentManagerTest {
@Test
public void downloadCallsJNIFunctionsWithFilenameFromManifest() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
doReturn(null).when(spyContext).getAssets();
Bundle bundle = new Bundle();
bundle.putString(ApplicationInfoLoader.PUBLIC_AOT_SHARED_LIBRARY_NAME, "custom_name.so");
bundle.putString(ApplicationInfoLoader.PUBLIC_FLUTTER_ASSETS_DIR_KEY, "custom_assets");
PackageManager packageManager = mock(PackageManager.class);
ApplicationInfo applicationInfo = mock(ApplicationInfo.class);
applicationInfo.metaData = bundle;
when(packageManager.getApplicationInfo(any(String.class), any(int.class)))
.thenReturn(applicationInfo);
doReturn(packageManager).when(spyContext).getPackageManager();
Context spyContext = createSpyContext(bundle);
doReturn(null).when(spyContext).getAssets();
String soTestFilename = "custom_name.so-123.part.so";
String soTestPath = "test/path/" + soTestFilename;
......@@ -148,11 +152,42 @@ public class PlayStoreDeferredComponentManagerTest {
assertEquals(jni.assetBundlePath, "custom_assets");
}
@Test
public void downloadCallsJNIFunctionsWithSharedLibraryNameFromManifest()
throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Bundle bundle = new Bundle();
bundle.putString(PlayStoreDeferredComponentManager.MAPPING_KEY, "123:module:custom_name.so");
bundle.putString(ApplicationInfoLoader.PUBLIC_FLUTTER_ASSETS_DIR_KEY, "custom_assets");
Context spyContext = createSpyContext(bundle);
doReturn(null).when(spyContext).getAssets();
String soTestFilename = "custom_name.so";
String soTestPath = "test/path/" + soTestFilename;
doReturn(new File(soTestPath)).when(spyContext).getFilesDir();
TestPlayStoreDeferredComponentManager playStoreManager =
new TestPlayStoreDeferredComponentManager(spyContext, jni);
jni.setDeferredComponentManager(playStoreManager);
assertEquals(jni.loadingUnitId, 0);
playStoreManager.installDeferredComponent(123, "TestModuleName");
assertEquals(jni.loadDartDeferredLibraryCalled, 1);
assertEquals(jni.updateAssetManagerCalled, 1);
assertEquals(jni.deferredComponentInstallFailureCalled, 0);
assertEquals(jni.searchPaths[0], soTestFilename);
assertTrue(jni.searchPaths[1].endsWith(soTestPath));
assertEquals(jni.searchPaths.length, 2);
assertEquals(jni.loadingUnitId, 123);
assertEquals(jni.assetBundlePath, "custom_assets");
}
@Test
public void searchPathsAddsApks() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
String apkTestPath = "test/path/TestModuleName_armeabi_v7a.apk";
doReturn(new File(apkTestPath)).when(spyContext).getFilesDir();
......@@ -176,8 +211,7 @@ public class PlayStoreDeferredComponentManagerTest {
@Test
public void invalidSearchPathsAreIgnored() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
String apkTestPath = "test/path/invalidpath.apk";
doReturn(new File(apkTestPath)).when(spyContext).getFilesDir();
......@@ -200,8 +234,8 @@ public class PlayStoreDeferredComponentManagerTest {
@Test
public void assetManagerUpdateInvoked() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
AssetManager assetManager = spyContext.getAssets();
String apkTestPath = "blah doesn't matter here";
doReturn(new File(apkTestPath)).when(spyContext).getFilesDir();
......@@ -222,8 +256,8 @@ public class PlayStoreDeferredComponentManagerTest {
@Test
public void stateGetterReturnsUnknowByDefault() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
doReturn(spyContext).when(spyContext).createPackageContext(any(), anyInt());
Context spyContext = createSpyContext(null);
doReturn(null).when(spyContext).getAssets();
TestPlayStoreDeferredComponentManager playStoreManager =
new TestPlayStoreDeferredComponentManager(spyContext, jni);
assertEquals(playStoreManager.getDeferredComponentInstallState(-1, "invalidName"), "unknown");
......@@ -232,7 +266,9 @@ public class PlayStoreDeferredComponentManagerTest {
@Test
public void loadingUnitMappingFindsMatch() throws NameNotFoundException {
TestFlutterJNI jni = new TestFlutterJNI();
Context spyContext = spy(RuntimeEnvironment.application);
Bundle bundle = new Bundle();
bundle.putString(PlayStoreDeferredComponentManager.MAPPING_KEY, "2:module1,5:module2");
Context spyContext = createSpyContext(bundle);
TestPlayStoreDeferredComponentManager playStoreManager =
new TestPlayStoreDeferredComponentManager(spyContext, jni);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册