@Override publicvoidinstallDeferredComponent(int loadingUnitId, String componentName) { StringresolvedComponentName= componentName != null ? componentName : loadingUnitIdToComponentNames.get(loadingUnitId); if (resolvedComponentName == null) { Log.e(TAG, "Deferred component name was null and could not be resolved from loading unit id."); return; } // Handle a loading unit that is included in the base module that does not need download. if (resolvedComponentName.equals("") && loadingUnitId > 0) { // No need to load assets as base assets are already loaded. loadDartLibrary(loadingUnitId, resolvedComponentName); return; } //耗时操作,模拟网络请求去下载android module newThread( () -> { //将so文件从外部存储移动到内部私有存储中 booleanresult= moveSoToPrivateDir(); if (result) { //模拟网络下载,添加2秒网络延迟 newHandler(Looper.getMainLooper()).postDelayed( () -> { loadAssets(loadingUnitId, resolvedComponentName); loadDartLibrary(loadingUnitId, resolvedComponentName); if (channel != null) { channel.completeInstallSuccess(resolvedComponentName); } } , 2000); } else { newHandler(Looper.getMainLooper()).post( () -> { Toast.makeText(context, "未在sd卡中找到so文件", Toast.LENGTH_LONG).show();
if (channel != null) { channel.completeInstallError(resolvedComponentName, "未在sd卡中找到so文件"); }
@Override publicvoidloadDartLibrary(int loadingUnitId, String componentName) { if (!verifyJNI()) { return; } // Loading unit must be specified and valid to load a dart library. //asset-only的component的unit id为-1,不需要加载so文件 if (loadingUnitId < 0) { return; }
//拿到so的文件名字 StringaotSharedLibraryName= 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"; }
//拿到支持的abi格式--arm64_v8a // Possible values: armeabi, armeabi-v7a, arm64-v8a, x86, x86_64, mips, mips64 String abi; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { abi = Build.SUPPORTED_ABIS[0]; } else { abi = Build.CPU_ABI; } StringpathAbi= abi.replace("-", "_"); // abis are represented with underscores in paths.
// TODO(garyq): Optimize this apk/file discovery process to use less i/o and be more // performant and robust.
// Search directly in APKs first List<String> apkPaths = newArrayList<>(); // If not found in APKs, we check in extracted native libs for the lib directly. List<String> soPaths = newArrayList<>();
Queue<File> searchFiles = newLinkedList<>(); // Downloaded modules are stored here--下载的 modules 存储位置 searchFiles.add(context.getFilesDir()); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) { //第一次通过appbundle形式安装的split apks位置 // The initial installed apks are provided by `sourceDirs` in ApplicationInfo. // The jniLibs we want are in the splits not the baseDir. These // APKs are only searched as a fallback, as base libs generally do not need // to be fully path referenced. for (String path : context.getApplicationInfo().splitSourceDirs) { searchFiles.add(newFile(path)); } }
//查找apk和so文件 while (!searchFiles.isEmpty()) { Filefile= searchFiles.remove(); if (file != null && file.isDirectory() && file.listFiles() != null) { for (File f : file.listFiles()) { searchFiles.add(f); } continue; } Stringname= file.getName(); // Special case for "split_config" since android base module non-master apks are // initially installed with the "split_config" prefix/name. if (name.endsWith(".apk") && (name.startsWith(componentName) || name.startsWith("split_config")) && name.contains(pathAbi)) { apkPaths.add(file.getAbsolutePath()); continue; } if (name.equals(aotSharedLibraryName)) { soPaths.add(file.getAbsolutePath()); } }
List<String> searchPaths = newArrayList<>();
// Add the bare filename as the first search path. In some devices, the so // file can be dlopen-ed with just the file name. searchPaths.add(aotSharedLibraryName);
for (String path : apkPaths) { searchPaths.add(path + "!lib/" + abi + "/" + aotSharedLibraryName); } for (String path : soPaths) { searchPaths.add(path); } //打开so文件 flutterJNI.loadDartDeferredLibrary(loadingUnitId, searchPaths.toArray(newString[searchPaths.size()])); }