Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.

Commit 42df4d0

Browse files
committed
Cleanup and API adjustments
1 parent 0d07cd8 commit 42df4d0

File tree

4 files changed

+101
-80
lines changed

4 files changed

+101
-80
lines changed

shell/platform/android/io/flutter/embedding/engine/FlutterJNI.java

Lines changed: 31 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -958,50 +958,65 @@ public void setDynamicFeatureContext(@NonNull Context context) {
958958
this.dynamicFeatureContext = context;
959959
}
960960

961-
// Called by the engine upon invocation of dart loadLibrary request
962961
@SuppressWarnings("unused")
963962
@UiThread
964-
public void downloadDynamicFeature(@NonNull String moduleName, int loadingUnitId) {
965-
dynamicFeatureManager.downloadModule(moduleName, loadingUnitId);
963+
public void downloadDynamicFeature(int loadingUnitId) {
964+
String loadingUnitIdResName = dynamicFeatureContext.getResources().getString(dynamicFeatureContext.getResources().getIdentifier("loadingUnit" + loadingUnitId, "string", dynamicFeatureContext.getPackageName()));
965+
downloadDynamicFeature(loadingUnitIdResName, loadingUnitId);
966966
}
967967

968+
// Called by the engine upon invocation of dart loadLibrary() request
968969
@SuppressWarnings("unused")
969970
@UiThread
970-
public void downloadDynamicFeature(int loadingUnitId) {
971-
String loadingUnitIdResName = dynamicFeatureContext.getResources().getString(dynamicFeatureContext.getResources().getIdentifier("loadingUnit" + loadingUnitId, "string", dynamicFeatureContext.getPackageName()));
972-
downloadDynamicFeature(loadingUnitIdResName, loadingUnitId);
971+
public void downloadDynamicFeature(String moduleName, int loadingUnitId) {
972+
dynamicFeatureManager.downloadFeature(moduleName, loadingUnitId);
973973
}
974974

975-
// This should be called for every loading unit to be loaded into the dart isolate.
975+
/**
976+
* This should be called for every loading unit to be loaded into the dart isolate.
977+
*
978+
* abi, libName, and apkPaths are used together to search the installed apks for the
979+
* desired .so library. If not found, soPath may be provided as a fallback if a
980+
* pre-extracted .so exists, especially on older devices with libs compressed in the
981+
* apk.
982+
*
983+
* assetManager and asserBundlePath are used to specify a new AssetManager that has
984+
* access to the dynamic feature's assets in addition to the base assets.
985+
*/
976986
@UiThread
977987
public void loadDartLibrary(
978988
int loadingUnitId,
979-
@NonNull String abi,
980989
@NonNull String libName,
990+
@NonNull String[] apkPaths,
991+
@NonNull String abi,
992+
@NonNull String soPath,
981993
@NonNull AssetManager assetManager,
982-
@NonNull String[] apkPaths) {
994+
@NonNull String assetBundlePath) {
983995
ensureRunningOnMainThread();
984996
ensureAttachedToNative();
985997
nativeLoadDartLibrary(
986998
nativePlatformViewId,
987999
loadingUnitId,
988-
abi,
9891000
libName,
1001+
apkPaths,
1002+
abi,
1003+
soPath,
9901004
assetManager,
991-
apkPaths);
992-
Log.e("flutter", "loadDartLibrary FlutterJNI");
1005+
assetBundlePath);
9931006
}
9941007
private native void nativeLoadDartLibrary(
9951008
long nativePlatformViewId,
9961009
int loadingUnitId,
997-
@NonNull String abi,
9981010
@NonNull String libName,
1011+
@NonNull String[] apkPaths,
1012+
@NonNull String abi,
1013+
@NonNull String soPath,
9991014
@NonNull AssetManager assetManager,
1000-
@NonNull String[] apkPaths);
1015+
@NonNull String assetBundlePath);
10011016

10021017
// Called when an install encounters a failure during the Android portion of installing a module.
1003-
// When transient is false, new attempts to install will automatically result in same error in dart before
1004-
// the request is passed to Android.
1018+
// When transient is false, new attempts to install will automatically result in same error in
1019+
// dart before the request is passed to Android.
10051020
@SuppressWarnings("unused")
10061021
@UiThread
10071022
public void dynamicFeatureInstallFailure(@NonNull String moduleName, int loadingUnitId, @NonNull String error, boolean trans) {

shell/platform/android/io/flutter/embedding/engine/dynamicfeatures/DynamicFeatureManager.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,20 +4,27 @@
44

55
package io.flutter.embedding.engine.dynamicfeatures;
66

7-
import androidx.annotation.NonNull;
8-
97
/**
10-
*
8+
* Basic interface that may be implemented to provide custom handling of dynamic features.
9+
*
10+
* The Flutter default implementation is PlayStoreDynamicFeatureManager.
11+
*
12+
* The methods here may be called independently or in a sequence one after the other to perform
13+
* a full install cycle of download, extract, and load dart libs.
1114
*/
1215
public interface DynamicFeatureManager {
16+
// Request that the feature module be downloaded and installed.
17+
public abstract void downloadFeature(String moduleName, int loadingUnitId);
1318

14-
// Requests that the module be downloaded.
15-
public abstract void downloadModule(@NonNull String moduleName, int loadingUnitId);
16-
17-
// Extracts any assets and resources from the module for use by Flutter.
18-
public abstract void extractModule(@NonNull String moduleName, int loadingUnitId);
19+
// Extract and load any assets and resources from the module for use by Flutter.
20+
// Depending on the structure of the feature module, there may or may not be assets
21+
// to extract.
22+
public abstract void extractFeature(String moduleName, int loadingUnitId);
1923

20-
// Loads the .so file into the Dart VM.
21-
public abstract void loadDartModules(@NonNull String moduleName, int loadingUnitId);
24+
// Load the .so shared library file into the Dart VM. Asset only features may skip this
25+
// step.
26+
public abstract void loadDartLibrary(String moduleName, int loadingUnitId);
2227

28+
// Uninstall the specified feature module.
29+
public abstract void uninstallFeature(String moduleName, int loadingUnitId);
2330
}

shell/platform/android/io/flutter/embedding/engine/dynamicfeatures/PlayStoreDynamicFeatureManager.java

Lines changed: 43 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@
3232
* Google Play store.
3333
*/
3434
public class PlayStoreDynamicFeatureManager implements DynamicFeatureManager {
35+
private static final String TAG = "flutter";
3536

3637
private @NonNull SplitInstallManager splitInstallManager;
3738
private @NonNull Map<Integer, String> sessionIdToName;
@@ -44,52 +45,53 @@ public class PlayStoreDynamicFeatureManager implements DynamicFeatureManager {
4445
private class FeatureInstallStateUpdatedListener implements SplitInstallStateUpdatedListener {
4546
public void onStateUpdate(SplitInstallSessionState state) {
4647
if (sessionIdToName.containsKey(state.sessionId())) {
48+
// TODO(garyq): Add capability to access the state from framework.
4749
switch (state.status()) {
4850
case SplitInstallSessionStatus.FAILED: {
49-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") install failed with " + state.errorCode());
51+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") install failed with " + state.errorCode());
5052
flutterJNI.dynamicFeatureInstallFailure(sessionIdToName.get(state.sessionId()), sessionIdToLoadingUnitId.get(state.sessionId()), "Module install failed with " + state.errorCode(), true);
5153
sessionIdToName.remove(state.sessionId());
5254
sessionIdToLoadingUnitId.remove(state.sessionId());
5355
break;
5456
}
5557
case SplitInstallSessionStatus.INSTALLED: {
56-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") installed successfully.");
57-
extractModule(sessionIdToName.get(state.sessionId()), sessionIdToLoadingUnitId.get(state.sessionId()));
58+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") installed successfully.");
59+
extractFeature(sessionIdToName.get(state.sessionId()), sessionIdToLoadingUnitId.get(state.sessionId()));
5860
sessionIdToName.remove(state.sessionId());
5961
sessionIdToLoadingUnitId.remove(state.sessionId());
6062
break;
6163
}
6264
case SplitInstallSessionStatus.CANCELED: {
63-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") cancelled");
65+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") cancelled");
6466
sessionIdToName.remove(state.sessionId());
6567
break;
6668
}
6769
case SplitInstallSessionStatus.CANCELING: {
68-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") canceling");
70+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") canceling");
6971
sessionIdToName.remove(state.sessionId());
7072
break;
7173
}
7274
case SplitInstallSessionStatus.PENDING: {
73-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") pending.");
75+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") pending.");
7476
break;
7577
}
7678
case SplitInstallSessionStatus.REQUIRES_USER_CONFIRMATION: {
77-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") requires user confirmation.");
79+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") requires user confirmation.");
7880
break;
7981
}
8082
case SplitInstallSessionStatus.DOWNLOADING: {
81-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") downloading.");
83+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") downloading.");
8284
break;
8385
}
8486
case SplitInstallSessionStatus.DOWNLOADED: {
85-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") downloaded.");
87+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") downloaded.");
8688
break;
8789
}
8890
case SplitInstallSessionStatus.INSTALLING: {
89-
Log.e("flutter", "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") installing.");
91+
Log.d(TAG, "Module \"" + sessionIdToName.get(state.sessionId()) + "\" (sessionId " + state.sessionId() + ") installing.");
9092
break;
9193
}
92-
default: Log.e("flutter", "Status: " + state.status());
94+
default: Log.d(TAG, "Status: " + state.status());
9395
}
9496
}
9597
}
@@ -105,8 +107,11 @@ public PlayStoreDynamicFeatureManager(@NonNull Context context, @NonNull Flutter
105107
sessionIdToLoadingUnitId = new HashMap();
106108
}
107109

108-
public void downloadModule(@NonNull String moduleName, int loadingUnitId) {
109-
Log.e("flutter", "INSTALLING MODULE " + moduleName + " " + flutterJNI);
110+
public void downloadFeature(String moduleName, int loadingUnitId) {
111+
if (moduleName == null) {
112+
Log.e(TAG, "Dynamic feature module name was null.");
113+
return;
114+
}
110115

111116
SplitInstallRequest request =
112117
SplitInstallRequest
@@ -124,53 +129,50 @@ public void downloadModule(@NonNull String moduleName, int loadingUnitId) {
124129
.addOnSuccessListener(sessionId -> {
125130
this.sessionIdToName.put(sessionId, moduleName);
126131
this.sessionIdToLoadingUnitId.put(sessionId, loadingUnitId);
127-
Log.e("flutter", "Request to install module \"" + moduleName + "\" sent with session id " + sessionId + ".");
132+
Log.d(TAG, "Request to install module \"" + moduleName + "\" sent with session id " + sessionId + ".");
128133
})
129134
.addOnFailureListener(exception -> {
130135
switch(((SplitInstallException) exception).getErrorCode()) {
131136
case SplitInstallErrorCode.NETWORK_ERROR:
132-
Log.e("flutter", "Install of dynamic feature module \"" + moduleName + "\" failed with a network error");
137+
Log.d(TAG, "Install of dynamic feature module \"" + moduleName + "\" failed with a network error");
133138
flutterJNI.dynamicFeatureInstallFailure(moduleName, loadingUnitId, "Install of dynamic feature module \"" + moduleName + "\" failed with a network error", true);
134139
break;
135140
case SplitInstallErrorCode.MODULE_UNAVAILABLE:
136-
Log.e("flutter", "Install of dynamic feature module \"" + moduleName + "\" failed as is unavailable.");
141+
Log.d(TAG, "Install of dynamic feature module \"" + moduleName + "\" failed as is unavailable.");
137142
flutterJNI.dynamicFeatureInstallFailure(moduleName, loadingUnitId, "Install of dynamic feature module \"" + moduleName + "\" failed as is unavailable.", false);
138143
break;
139144
default:
140-
Log.e("flutter", "Install of dynamic feature module \"" + moduleName + "\" failed with error: \"" + ((SplitInstallException) exception).getErrorCode() + "\": " + ((SplitInstallException) exception).getMessage());
145+
Log.d(TAG, "Install of dynamic feature module \"" + moduleName + "\" failed with error: \"" + ((SplitInstallException) exception).getErrorCode() + "\": " + ((SplitInstallException) exception).getMessage());
141146
flutterJNI.dynamicFeatureInstallFailure(moduleName, loadingUnitId, "Install of dynamic feature module \"" + moduleName + "\" failed with error: \"" + ((SplitInstallException) exception).getErrorCode() + "\": " + ((SplitInstallException) exception).getMessage(), false);
142147
break;
143148
}
144149
});
145150
}
146151

147-
public void extractModule(@NonNull String moduleName, int loadingUnitId) {
148-
Log.e("flutter", "Extracting \"" + moduleName + "\" " + flutterJNI);
149-
152+
public void extractFeature(@NonNull String moduleName, int loadingUnitId) {
150153
try {
151154
context = context.createPackageContext(context.getPackageName(), 0);
152155
// We only load dart shared lib for the loading unit id requested. Other loading units in the
153156
// dynamic feature module are not loaded, but can be loaded by calling again with their loading
154157
// unit id.
155-
loadDartModules(moduleName, loadingUnitId);
158+
loadDartLibrary(moduleName, loadingUnitId);
156159
} catch (NameNotFoundException e) {
157-
Log.e("flutter", "NameNotFoundException creating context for " + moduleName);
160+
Log.d(TAG, "NameNotFoundException creating context for " + moduleName);
158161
throw new RuntimeException(e);
159162
}
160163
// TODO: Handle assets here.
161164
}
162165

163-
public void loadDartModules(@NonNull String moduleName, int loadingUnitId) {
164-
Log.e("flutter", "Loading dart modules \"" + moduleName + "\" " + flutterJNI);
166+
public void loadDartLibrary(String moduleName, int loadingUnitId) {
165167
// This matches/depends on dart's loading unit naming convention, which we use unchanged.
166168
String aotSharedLibraryName = "app.so-" + loadingUnitId + ".part.so";
167169

168170
// Possible values: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64
169171
String abi;
170-
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) {
171-
abi = Build.CPU_ABI;
172-
} else {
172+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
173173
abi = Build.SUPPORTED_ABIS[0];
174+
} else {
175+
abi = Build.CPU_ABI;
174176
}
175177
String pathAbi = abi.replace("-", "_"); // abis are represented with underscores in paths.
176178

@@ -198,19 +200,22 @@ public void loadDartModules(@NonNull String moduleName, int loadingUnitId) {
198200
}
199201
}
200202

201-
// Usefull logging for development. Remove later.
202-
Log.e("flutter", "");
203-
Log.e("flutter", "APKs " + apkPaths.size());
204-
for (String s : apkPaths) Log.e("flutter", s);
205-
Log.e("flutter", "");
206-
Log.e("flutter", "SO: " + soPath);
207-
Log.e("flutter", "");
208-
Log.e("flutter", "ARCH: " + abi);
209-
Log.e("flutter", "");
210-
203+
// TODO(garyq): Handle assets in extractModule() above;
211204
AssetManager assetManager = context.getAssets();
212205

213-
flutterJNI.loadDartLibrary(loadingUnitId, abi, aotSharedLibraryName, assetManager, apkPaths.toArray(new String[apkPaths.size()]));
206+
flutterJNI.loadDartLibrary(
207+
loadingUnitId,
208+
aotSharedLibraryName,
209+
apkPaths.toArray(new String[apkPaths.size()]),
210+
abi,
211+
soPath,
212+
assetManager,
213+
// TODO(garyq): Made the "flutter_assets" directory dynamic based off of DartEntryPoint.
214+
"flutter_assets");
215+
}
216+
217+
public void uninstallFeature(String moduleName, int loadingUnitId) {
218+
// TODO(garyq): support uninstalling.
214219
}
215220

216221
void destroy() {

shell/platform/android/platform_view_android_jni_impl.cc

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -520,17 +520,17 @@ static void LoadDartLibrary(JNIEnv* env,
520520
jobject obj,
521521
jlong shell_holder,
522522
jint jLoadingUnitId,
523-
jstring jAbi,
524523
jstring jLibName,
524+
jobjectArray jApkPaths,
525+
jstring jAbi,
526+
jstring jSoPath,
525527
jobject jAssetManager,
526-
jobjectArray jApkPaths) {
527-
// see RunBundleAndSnapshotFromLibrary above for dart loading code
528+
jstring jAssetBundlePath) {
528529
auto asset_manager = std::make_shared<flutter::AssetManager>();
529-
530530
asset_manager->PushBack(std::make_unique<flutter::APKAssetProvider>(
531-
env, // jni environment
532-
jAssetManager, // asset manager
533-
"flutter_assets") // apk asset dir TODO: Pass in as parameter
531+
env, // jni environment
532+
jAssetManager, // asset manager
533+
fml::jni::JavaStringToString(env, jAssetBundlePath)) // apk asset dir
534534
);
535535

536536
std::string abi = fml::jni::JavaStringToString(env, jAbi);
@@ -543,14 +543,7 @@ static void LoadDartLibrary(JNIEnv* env,
543543
fml::jni::JavaStringToString(env, jLibName), apkPaths, abi,
544544
std::move(asset_manager));
545545

546-
// asset_manager->PushBack(std::make_unique<flutter::APKAssetProvider>(
547-
// env, // jni environment
548-
// jAssetManager, // asset manager
549-
// fml::jni::JavaStringToString(env, jBundlePath)) // apk asset dir
550-
// );
551-
552-
// RunConfiguration config(std::move(isolate_configuration),
553-
// std::move(asset_manager));
546+
// TODO(garyq): fallback on soPath.
554547
}
555548

556549
static void DynamicFeatureInstallFailure(JNIEnv* env,
@@ -559,8 +552,9 @@ static void DynamicFeatureInstallFailure(JNIEnv* env,
559552
jint loadigUnitId,
560553
jobject error,
561554
jboolean transient) {
562-
// TODO: Implement
555+
// TODO(garyq): Implement
563556
}
557+
564558
bool RegisterApi(JNIEnv* env) {
565559
static const JNINativeMethod flutter_jni_methods[] = {
566560
// Start of methods from FlutterJNI

0 commit comments

Comments
 (0)