[TOC]

概述

在Google发布Flutter之后我一直对它保持很高的热情,尤其是Flutter支持热更新,但在1.7.8版本之后由于某些原因Google屏蔽了热更新功能,
这着实让让人失落……于是抽了点时间研究了一下Flutter的加载过程,目的是找到可以实现热更新的方式.

Flutter的版本

这次研究的是基于目前稳定的版本1.12.13-hotfix9

1
2
3
4
Flutter 1.12.13+hotfix.9 • channel stable • https://github.com/flutter/flutter.git
Framework • revision f139b11009 (3 weeks ago) • 2020-03-30 13:57:30 -0700
Engine • revision af51afceb8
Tools • Dart 2.7.2

要实现Flutter的热更新功能就要先弄清楚Flutter的加载流程,比如Flutter引擎什么时机加载,引擎加载完毕后libapp.so文件什么时机加载等,因此我们先分析一下Flutter的加载过程。

Android工程启动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
<application
android:name="io.flutter.app.FlutterApplication"
android:label="free_ctrip"
android:icon="@mipmap/ic_launcher">
<activity
android:name=".MainActivity"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">

<!-- This keeps the window background of the activity showing
until Flutter renders its first frame. It can be removed if
there is no splash screen (such as the default splash screen
defined in @style/LaunchTheme). -->
<meta-data
android:name="io.flutter.app.android.SplashScreenUntilFirstFrame"
android:value="true" />
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
</application>

Manifest默认配置了当前项目的Application为FlutterApplication,启动页面是MainActivity,另外配置的meta-data信息我们先不关注,我们先看FlutterApplication类(在flutter.jar包中),如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class FlutterApplication extends Application {
@Override
@CallSuper
public void onCreate() {
super.onCreate();
FlutterMain.startInitialization(this);
}

private Activity mCurrentActivity = null;
public Activity getCurrentActivity() {
return mCurrentActivity;
}
public void setCurrentActivity(Activity mCurrentActivity) {
this.mCurrentActivity = mCurrentActivity;
}
}

FlutterApplication继承Application,它定义了Activity类型的mCurrentActivity属性并给其添加了set/get方法,
另外FlutterApplication重写了onCreate()方法,在onCreate()方法中仅调用了FlutterMain的startInitialization()静态方法进行初始化操作,FlutterMain源码如下:

FlutterMain的开始初始化

FlutterMain定义了一系列静态方法,而这些方法内部又委托FlutterLoader实现具体功能,FlutterLoader看名字就知道是一个加载类,它可能是我们实现热更新的入口类。
FlutterLoader对外提供了一个静态的getInstance()方法便于获取其实例(该方法是单例的),其startInitialization()源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
public class FlutterMain {

public static class Settings {
private String logTag;

@Nullable
public String getLogTag() {
return logTag;
}

/**
* Set the tag associated with Flutter app log messages.
* @param tag Log tag.
*/
public void setLogTag(String tag) {
logTag = tag;
}
}

public static void startInitialization(@NonNull Context applicationContext) {
if (isRunningInRobolectricTest) {
return;
}
FlutterLoader.getInstance().startInitialization(applicationContext);
}

public static void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
if (isRunningInRobolectricTest) {
return;
}
FlutterLoader.Settings newSettings = new FlutterLoader.Settings();
newSettings.setLogTag(settings.getLogTag());
FlutterLoader.getInstance().startInitialization(applicationContext, newSettings);
}

我们可以看到这个方法比较简单,就是简单的调用了

1
FlutterLoader.getInstance().startInitialization(applicationContext, newSettings);

所以,我们来看看FlutterLoader里面的startInitialization的实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
public void startInitialization(@NonNull Context applicationContext, @NonNull Settings settings) {
// Do not run startInitialization more than once.
// 多次调用的判断
if (this.settings != null) {
return;
}
// 保证主线程启动
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("startInitialization must be called on the main thread");
}
// 暂存设置对象
this.settings = settings;
// 启动计时
long initStartTimestampMillis = SystemClock.uptimeMillis();
// 初始化源数据配置
initConfig(applicationContext);
// 初始化资源文件
initResources(applicationContext);
// 加载flutter.so flutter引擎
System.loadLibrary("flutter");

VsyncWaiter
.getInstance((WindowManager) applicationContext.getSystemService(Context.WINDOW_SERVICE))
.init();

// We record the initialization time using SystemClock because at the start of the
// initialization we have not yet loaded the native library to call into dart_tools_api.h.
// To get Timeline timestamp of the start of initialization we simply subtract the delta
// from the Timeline timestamp at the current moment (the assumption is that the overhead
// of the JNI call is negligible).
long initTimeMillis = SystemClock.uptimeMillis() - initStartTimestampMillis;
// 为什么Native层要记录这个启动的时间差??
FlutterJNI.nativeRecordStartTimestamp(initTimeMillis);
}


private void initConfig(@NonNull Context applicationContext) {
// manifestfile.XML的源数据解析
Bundle metadata = getApplicationInfo(applicationContext).metaData;

// There isn't a `<meta-data>` tag as a direct child of `<application>` in
// `AndroidManifest.xml`.
if (metadata == null) {
return;
}
// 这些源数据的解析,我们后续分析
aotSharedLibraryName = metadata.getString(PUBLIC_AOT_SHARED_LIBRARY_NAME, DEFAULT_AOT_SHARED_LIBRARY_NAME);
flutterAssetsDir = metadata.getString(PUBLIC_FLUTTER_ASSETS_DIR_KEY, DEFAULT_FLUTTER_ASSETS_DIR);

vmSnapshotData = metadata.getString(PUBLIC_VM_SNAPSHOT_DATA_KEY, DEFAULT_VM_SNAPSHOT_DATA);
isolateSnapshotData = metadata.getString(PUBLIC_ISOLATE_SNAPSHOT_DATA_KEY, DEFAULT_ISOLATE_SNAPSHOT_DATA);
}

/**
* Extract assets out of the APK that need to be cached as uncompressed
* files on disk.
*/
private void initResources(@NonNull Context applicationContext) {
// 先清空资源
new ResourceCleaner(applicationContext).start();
// 只在DEBUG或者JIT_RELEASE模式下执行
if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
final String dataDirPath = PathUtils.getDataDirectory(applicationContext);
final String packageName = applicationContext.getPackageName();
final PackageManager packageManager = applicationContext.getPackageManager();
final AssetManager assetManager = applicationContext.getResources().getAssets();
resourceExtractor = new ResourceExtractor(dataDirPath, packageName, packageManager, assetManager);

// In debug/JIT mode these assets will be written to disk and then
// mapped into memory so they can be provided to the Dart VM.
// 虚拟机快照数据??
// 隔离快照数据
resourceExtractor
.addResource(fullAssetPathFrom(vmSnapshotData))
.addResource(fullAssetPathFrom(isolateSnapshotData))
.addResource(fullAssetPathFrom(DEFAULT_KERNEL_BLOB));

resourceExtractor.start();
}
}

FlutterActivity启动

到这里我们分析完了Flutter引擎的加载时机,然而我们Flutter项目打包出来的libapp.so还没有被加载,那它是什么时机加载的呢?我们继续往下分析代码,
根据Manifest的配置,启动页面配置的是MainActivity,因此我们需要分析下MainActivity,它的源码如下所示:

1
2
3
4
5
6
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
GeneratedPluginRegistrant.registerWith(flutterEngine);
}
}

MainActivity继承FlutterActivity,它仅重写了configureFlutterEngine()方法,
一般情况下创建完Activity后会在其onCreate()方法中调用setContentView()为当前Activity添加视图,
可MainActivity没有重写onCreate()方法也没setContentView()的调用并且项目运行后界面正常渲染,
那只能说明它的父类FlutterActivity调用了setContentView()方法,我们看下FlutterActivity的源码,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
public class FlutterActivity extends Activity
implements FlutterActivityAndFragmentDelegate.Host,
LifecycleOwner {
private static final String TAG = "FlutterActivity";

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();

super.onCreate(savedInstanceState);

lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
// 实例化FlutterActivityAndFragmentDelegate。并持有当前宿主对象
// 封装了宿主Activity的一些特殊属性
delegate = new FlutterActivityAndFragmentDelegate(this);
// delegate绑定当前的Activity
// attach传入的this是没用的。主要绑定关系还是在上面
delegate.onAttach(this);

delegate.onActivityCreated(savedInstanceState);

configureWindowForTransparency();
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}

@NonNull
private View createFlutterView() {
return delegate.onCreateView(
null /* inflater */,
null /* container */,
null /* savedInstanceState */);
}

@Override
protected void onStart() {
super.onStart();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_START);
delegate.onStart();
}

@Override
protected void onResume() {
super.onResume();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_RESUME);
delegate.onResume();
}

@Override
public void onPostResume() {
super.onPostResume();
delegate.onPostResume();
}

@Override
protected void onPause() {
super.onPause();
delegate.onPause();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_PAUSE);
}

@Override
protected void onStop() {
super.onStop();
delegate.onStop();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_STOP);
}

@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
delegate.onSaveInstanceState(outState);
}

@Override
protected void onDestroy() {
super.onDestroy();
delegate.onDestroyView();
delegate.onDetach();
lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
}
}

FlutterActivityAndFragmentDelegate实例化

FlutterActivity继承Activity并实现了Host和LifecycleOwner接口并定义了一个重量级属性delegate,
delegate是FlutterActivityAndFragmentDelegate类型,它是FlutterActivity的大管家,
FlutterActivity的众多回调都委托给了delegate,FlutterActivityAndFragmentDelegate构造方法如下所示:

1
2
3
4
5
6
7
8
9
final class FlutterActivityAndFragmentDelegate {

// host就是我们传递进来的FlutterActivity实例
private Host host;

FlutterActivityAndFragmentDelegate(@NonNull Host host) {
this.host = host;
}
}

我们看到FlutterActivityAndFragmentDelegate的构造函数持有了Host对象。通过上面的源码我们可以知道。
这个Host其实就是FLutterActivity的宿主实例

FlutterActivity的onCreate方法学习

我们继续看FlutterActivity的onCreate()方法,初始化delegate的时候传递的this(也就是delegate持有了当前FlutterActivity对象),
初始化后依次调用了它的onAttach()和onActivityCreated()方法,最后调用了setContentView()方法为当前Activity添加视图,
而在调用setContentView()的时候也是委托delegate的onCreateView()方法给当前当前Activity创建视图。
我们先看下delegate的onAttach()方法,源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
switchLaunchThemeForNormalTheme();

super.onCreate(savedInstanceState);

lifecycle.handleLifecycleEvent(Lifecycle.Event.ON_CREATE);
// 实例化FlutterActivityAndFragmentDelegate。并持有当前宿主对象
// 封装了宿主Activity的一些特殊属性
delegate = new FlutterActivityAndFragmentDelegate(this);
// delegate绑定当前的Activity
// attach传入的this是没用的。主要绑定关系还是在上面
delegate.onAttach(this);

delegate.onActivityCreated(savedInstanceState);

configureWindowForTransparency();
setContentView(createFlutterView());
configureStatusBarForFullscreenFlutterExperience();
}

FlutterActivityAndFragmentDelegate的onAttach方法学习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void onAttach(@NonNull Context context) {
// host == null 为什么??
ensureAlive();

// When "retain instance" is true, the FlutterEngine will survive configuration
// changes. Therefore, we create a new one only if one does not already exist.
if (flutterEngine == null) {
// Flutter引擎的创建以及实例化
setupFlutterEngine();
}

platformPlugin = host.providePlatformPlugin(host.getActivity(), flutterEngine);

if (host.shouldAttachEngineToActivity()) {
Log.d(TAG, "Attaching FlutterEngine to the Activity that owns this Fragment.");
flutterEngine.getActivityControlSurface().attachToActivity(
host.getActivity(),
host.getLifecycle()
);
}

host.configureFlutterEngine(flutterEngine);
}

FlutterActivityAndFragmentDelegate的setupFlutterEngine方法学习

onAttach()方法首先调用ensureAlive()确保host实例化过,然后判断flutterEngine是否初始化过,
在应用首次启动时flutterEngine为null,所以执行setupFlutterEngine()先初始化flutterEngine

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/* package */ void setupFlutterEngine() {
Log.d(TAG, "Setting up FlutterEngine.");

// First, check if the host wants to use a cached FlutterEngine.
// 首先检查Host是否需要使用缓存的引擎。
// 这个就是我们为什么要构建缓存引擎的时候一定要传ID的原因
String cachedEngineId = host.getCachedEngineId();
if (cachedEngineId != null) {
// 从引擎池里面取出引擎
flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
isFlutterEngineFromHost = true;
if (flutterEngine == null) {
throw new IllegalStateException("The requested cached FlutterEngine did not exist in the FlutterEngineCache: '" + cachedEngineId + "'");
}
return;
}
// 很好理解,上面如果已经有了缓冲引擎池,那么下面我们就不需要构建了。
// Second, defer to subclasses for a custom FlutterEngine.
// 第二步,再检查host提供的flutter的引擎
flutterEngine = host.provideFlutterEngine(host.getContext());
if (flutterEngine != null) {
isFlutterEngineFromHost = true;
return;
}

// Our host did not provide a custom FlutterEngine. Create a FlutterEngine to back our
// FlutterView.
Log.d(TAG, "No preferred FlutterEngine was provided. Creating a new FlutterEngine for"
+ " this FlutterFragment.");
// 只有不使用缓存的FlutterEngine.也不使用flutterActivity提供的FlutterEngine。
// FlutterEngine才在最后一步创建
flutterEngine = new FlutterEngine(host.getContext(), host.getFlutterShellArgs().toArray());
isFlutterEngineFromHost = false;
}

setupFlutterEngine()方法的职责是初始化flutterEngine,首先根据host的getCachedEngineId()方法判断是否使用缓存的FlutterEngine,
因为host是FlutterActivity实例而FlutterActivity的getCachedEngineId()方法通过Intent获取的,默认返回的是null,
所以接着执行host的provideFlutterEngine()方法,而FlutterActivity的provideFlutterEngine()方法默认返回的也是null,
所以最后直接调用了FlutterEngine的两个参数的构造方法创建一个FlutterEngine实例。

FlutterEngine对象实例化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
public FlutterEngine(
@NonNull Context context,
@NonNull FlutterLoader flutterLoader, //加载flutter资源的加载器
@NonNull FlutterJNI flutterJNI, // flutter的Java和C/C++的通信结构
@Nullable String[] dartVmArgs, // flutterVM虚拟机启动擦书
boolean automaticallyRegisterPlugins // 自动注入插件
) {
//
this.flutterJNI = flutterJNI;
// FlutterLoader的初始化的相关操作
// 这个方法可能多次调用。如果是默认的flutter程序的时候
// 我们可能会在Application里面进行实例化
flutterLoader.startInitialization(context);
// 保证flutterLoader的初始化完成
// 调用FlutterLoader的ensureInitializationComplete()方法加载Flutter引擎需要的资源文件libapp.so
flutterLoader.ensureInitializationComplete(context, dartVmArgs);
// 添加Flutter引擎的生命周期监听器
flutterJNI.addEngineLifecycleListener(engineLifecycleListener);
//绑定到JNI??这是什么逻辑??
attachToJni();
// 实例化Dart的执行器
this.dartExecutor = new DartExecutor(flutterJNI, context.getAssets());
this.dartExecutor.onAttachedToJNI();

// TODO(mattcarroll): FlutterRenderer is temporally coupled to attach(). Remove that coupling if possible.
this.renderer = new FlutterRenderer(flutterJNI);

accessibilityChannel = new AccessibilityChannel(dartExecutor, flutterJNI);
keyEventChannel = new KeyEventChannel(dartExecutor);
lifecycleChannel = new LifecycleChannel(dartExecutor);
localizationChannel = new LocalizationChannel(dartExecutor);
navigationChannel = new NavigationChannel(dartExecutor);
platformChannel = new PlatformChannel(dartExecutor);
settingsChannel = new SettingsChannel(dartExecutor);
systemChannel = new SystemChannel(dartExecutor);
textInputChannel = new TextInputChannel(dartExecutor);

platformViewsController = new PlatformViewsController();
// 实例化pluginRegistry。传入的参数有context
this.pluginRegistry = new FlutterEnginePluginRegistry(
context.getApplicationContext(),
this,
flutterLoader
);
// 判断是否需要自动注入plugins
if (automaticallyRegisterPlugins) {
registerPlugins();
}
}

FlutterEngine目前提供了三个构造方法,最后执行的是含有4个参数的构造方法,

  • 构造方法内部调用了FlutterLoader的startInitialization()和ensureInitializationComplete()方法,再次调用startInitialization()的目的是保证Flutter引擎已经加载过。
  • 添加Flutter引擎的生命周期监听器
  • 绑定到JNI?
  • 实例化Dart的执行器
  • 实例化FlutterRenderer对象
  • 实例化各种Channel对象
  • 判断是否需要自动注入plugins注册Plugin

这个对象的构造方法非常重要,我们下面逐步来解析这个构造函数的每个功能。

之前,我们已经解析了FlutterLoader的startInitialization的方法。这个方法可能多次调用。如果是默认的flutter程序的时候
我们可能会在Application里面进行实例化

FlutterLoader的ensureInitializationComplete方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* Blocks until initialization of the native system has completed.
* <p>
* Calling this method multiple times has no effect.
*
* @param applicationContext The Android application context.
* @param args Flags sent to the Flutter runtime.
*/
public void ensureInitializationComplete(@NonNull Context applicationContext, @Nullable String[] args) {
// 用一个标志变量来标记是否初始化过
if (initialized) {
return;
}
// 保证主线程的调用
if (Looper.myLooper() != Looper.getMainLooper()) {
throw new IllegalStateException("ensureInitializationComplete must be called on the main thread");
}
// 保证必须调用过startInitialization()方法
if (settings == null) {
throw new IllegalStateException("ensureInitializationComplete must be called after startInitialization");
}
try {
// 只有在DEBUG或者JIT_RELEASE模式下resourceExtractor才非空
if (resourceExtractor != null) {
resourceExtractor.waitForCompletion();
}
//初始化shell参数
List<String> shellArgs = new ArrayList<>();
shellArgs.add("--icu-symbol-prefix=_binary_icudtl_dat");

ApplicationInfo applicationInfo = getApplicationInfo(applicationContext);
shellArgs.add("--icu-native-lib-path=" + applicationInfo.nativeLibraryDir + File.separator + DEFAULT_LIBRARY);

if (args != null) {
Collections.addAll(shellArgs, args);
}

String kernelPath = null;
if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) {
// 在DEBUG或者JIT_RELEASE模式下加载asset下的资源
String snapshotAssetPath = PathUtils.getDataDirectory(applicationContext) + File.separator + flutterAssetsDir;
kernelPath = snapshotAssetPath + File.separator + DEFAULT_KERNEL_BLOB;
shellArgs.add("--" + SNAPSHOT_ASSET_PATH_KEY + "=" + snapshotAssetPath);
shellArgs.add("--" + VM_SNAPSHOT_DATA_KEY + "=" + vmSnapshotData);
shellArgs.add("--" + ISOLATE_SNAPSHOT_DATA_KEY + "=" + isolateSnapshotData);
} else {
// RELEASE模式下加载nativeLibraryDir下的libapp.so文件
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + aotSharedLibraryName);

// Most devices can load the AOT shared library based on the library name
// with no directory path. Provide a fully qualified path to the library
// as a workaround for devices where that fails.
//这里很重要,如果libapp.so加载失败,可以设置libapp.so的全路径
shellArgs.add("--" + AOT_SHARED_LIBRARY_NAME + "=" + applicationInfo.nativeLibraryDir + File.separator + aotSharedLibraryName);
}

shellArgs.add("--cache-dir-path=" + PathUtils.getCacheDirectory(applicationContext));
if (settings.getLogTag() != null) {
shellArgs.add("--log-tag=" + settings.getLogTag());
}

String appStoragePath = PathUtils.getFilesDir(applicationContext);
String engineCachesPath = PathUtils.getCacheDirectory(applicationContext);
// nativeInit开始执行nativeInit
// 调用native方法加载libapp.so 并且传入上面shell参数
FlutterJNI.nativeInit(applicationContext, shellArgs.toArray(new String[0]),
kernelPath, appStoragePath, engineCachesPath);

initialized = true;
} catch (Exception e) {
Log.e(TAG, "Flutter initialization failed.", e);
throw new RuntimeException(e);
}
}

ensureInitializationComplete()方法和startInitialization()方法套路是一样的,它根据initialized字段防止多次调用,
程序首次执行的时候initialized为false所以正常往下走,首先校验settings时候为null,
因为settings是在startInitialization()方法中初始化的,如果为null就表示startInitialization()方法没有调用则直接抛异常。

接着是判断resourceExtractor是否为null,resourceExtractor只有在DEBUG和JIT_RELEASE模式下才会初始化,所以此时resourceExtractor为null,

然后定义了shellArgs集合,该集合装载的是Flutter引擎所需参数

继续看代码,在给shellArgs添加参数的时候有个判断,当编译模式为DEBUG和JIT_RELEASE的时候添加的参数和RELEASE模式下添加的参数是不同的,
RELEASE模式下添加的是AOT_SHARED_LIBRARY_NAME参数并且该参数添加了两次,

第一次添加的参数值是aotSharedLibraryName的值(aotSharedLibraryName在initConfig()进行的初始化,默认是libapp.so),

第二次添加的值是applicationInfo.nativeLibraryDir + File.separator + aotSharedLibraryName,也就是libapp.so的全路径,

在仔细看第二次添加AOT_SHARED_LIBRARY_NAME参数前的一段注释,这个注释的信息非常重要.

根据注释我们可以得到一个非常重要的结论:第二次添加AOT_SHARED_LIBRARY_NAME参数的目的是兜底操作,就是第一次直接加载libapp.so库失败的时候Flutter引擎会再次尝试加载全路径的libapp.so库,

从而防止libapp.so加载失败。根据这个结论我们可以思考一下,如果让第一次加载失败,也即是让aotSharedLibraryName传一个错误的值,

然后第二次传递一个我们指定的路径值,那么Flutter引擎加载的就是我们指定的libapp.so了,这也就可以实现Flutter的热更新了!有了这个思路我们接下来就是考虑如何修改这个全路径的值。

代码分析到这我们知道了libapp.so是在FlutterActivity的onCreate()方法中被加载的,具体加载是通过FlutterLoader的ensureInitializationComplete()方法实现的,

最后,调用 FlutterJNI.nativeInit(applicationContext, shellArgs.toArray(new String[0]),kernelPath, appStoragePath, engineCachesPath); 这个Native方法来
进行flutter的初始化。

文章参考:Flutter源码系列之《一》Flutter的热更新探索(上)