magicbaby810 / HotfixFlutter

使用Tinker或Sophix实现Flutter热更新,兼容flutterboost
400 stars 51 forks source link

请问有试过1.22.4版本的Flutter的吗? #13

Closed Notzuonotdied closed 3 years ago

Notzuonotdied commented 3 years ago

我看了下,1.22.4版本版本的源码做了改动。

你这一块的代码已经没法使用了。

    public static void reflect(String libPath) {
        try {
            FlutterLoader flutterLoader = FlutterLoader.getInstance();

            Field field = FlutterLoader.class.getDeclaredField("aotSharedLibraryName");
            field.setAccessible(true);
            field.set(flutterLoader, libPath);

            TinkerLog.i(TAG, "flutter patch is loaded successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这一块有计划修复么?

1.17源码 ```java // Mutable because default values can be overridden via config properties private String aotSharedLibraryName = DEFAULT_AOT_SHARED_LIBRARY_NAME; public void ensureInitializationComplete( @NonNull Context applicationContext, @Nullable String[] args) { try { if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) { } else { 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. shellArgs.add( "--" + AOT_SHARED_LIBRARY_NAME + "=" + applicationInfo.nativeLibraryDir + File.separator + aotSharedLibraryName); } } catch (Exception e) { Log.e(TAG, "Flutter initialization failed.", e); throw new RuntimeException(e); } } ```
1.22.4源码 ```java private FlutterApplicationInfo flutterApplicationInfo; public void ensureInitializationComplete( @NonNull Context applicationContext, @Nullable String[] args) { try { if (BuildConfig.DEBUG || BuildConfig.JIT_RELEASE) { } else { shellArgs.add( "--" + AOT_SHARED_LIBRARY_NAME + "=" + flutterApplicationInfo.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. shellArgs.add( "--" + AOT_SHARED_LIBRARY_NAME + "=" + flutterApplicationInfo.nativeLibraryDir + File.separator + flutterApplicationInfo.aotSharedLibraryName); } } catch (Exception e) { Log.e(TAG, "Flutter initialization failed.", e); throw new RuntimeException(e); } } ```
Notzuonotdied commented 3 years ago

看了源码,不需要反射也可以解决:

原理解析:

        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.
        shellArgs.add(
            "--"
                + AOT_SHARED_LIBRARY_NAME
                + "="
                + applicationInfo.nativeLibraryDir
                + File.separator
                + aotSharedLibraryName);
magicbaby810 commented 3 years ago

明天看看

heroghost commented 3 years ago

看了源码,不需要反射也可以解决:

  • args中存入一个参数--aot-shared-library-name=so的路径,这样子引擎初始化的时候,拿到的就是自定义的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.
        shellArgs.add(
            "--"
                + AOT_SHARED_LIBRARY_NAME
                + "="
                + applicationInfo.nativeLibraryDir
                + File.separator
                + aotSharedLibraryName);
  • 这一块的代码其实传了两次AOT_SHARED_LIBRARY_NAME,虚拟机在解析参数的时候,会优先加载最前的参数,然后逐个尝试load。

你好,没看明白你的方法。新版本的flutter下,属性名不一致,FlutterLoader没有aotSharedLibraryName, 没看明白你是怎么解决的。

magicbaby810 commented 3 years ago

看了源码,不需要反射也可以解决:

  • args中存入一个参数--aot-shared-library-name=so的路径,这样子引擎初始化的时候,拿到的就是自定义的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.
        shellArgs.add(
            "--"
                + AOT_SHARED_LIBRARY_NAME
                + "="
                + applicationInfo.nativeLibraryDir
                + File.separator
                + aotSharedLibraryName);
  • 这一块的代码其实传了两次AOT_SHARED_LIBRARY_NAME,虚拟机在解析参数的时候,会优先加载最前的参数,然后逐个尝试load。

你好,没看明白你的方法。新版本的flutter下,属性名不一致,FlutterLoader没有aotSharedLibraryName, 没看明白你是怎么解决的。

这几天更新吧,办法还是有的。核心思想就是利用反射把补丁so包的路径给塞进去,让flutter加载就行了。你也可以自己试着实现,没必要照着我的来

heroghost commented 3 years ago
        Field field = FlutterLoader.class.getDeclaredField("flutterApplicationInfo");
        field.setAccessible(true);
        Class<?> flutterApplicationInfoClass = null;
        if(field.get(flutterLoader) != null) {
            flutterApplicationInfoClass = field.get(flutterLoader).getClass();
            Field aotSharedLibraryNameField = flutterApplicationInfoClass.getDeclaredField("aotSharedLibraryName");
            aotSharedLibraryNameField.setAccessible(true);
            aotSharedLibraryNameField.set(field.get(flutterLoader), libPath);
            field.set(flutterLoader, field.get(flutterLoader));
        } else {
            Method method = FlutterLoader.class.getDeclaredMethod("startInitialization", Context.class);
            method.invoke(flutterLoader, context);

            flutterApplicationInfoClass = field.get(flutterLoader).getClass();
            Field aotSharedLibraryNameField = flutterApplicationInfoClass.getDeclaredField("aotSharedLibraryName");
            aotSharedLibraryNameField.setAccessible(true);
            aotSharedLibraryNameField.set(field.get(flutterLoader), libPath);
            field.set(flutterLoader, field.get(flutterLoader));
        }
heroghost commented 3 years ago

这样解决了

heroghost commented 3 years ago

我现在在想怎么把纯Flutter改成热更新

heroghost commented 3 years ago

请问跳转flutter页面是怎么设置的?

magicbaby810 commented 3 years ago

我看了下,1.22.4版本版本的源码做了改动。

你这一块的代码已经没法使用了。

    public static void reflect(String libPath) {
        try {
            FlutterLoader flutterLoader = FlutterLoader.getInstance();

            Field field = FlutterLoader.class.getDeclaredField("aotSharedLibraryName");
            field.setAccessible(true);
            field.set(flutterLoader, libPath);

            TinkerLog.i(TAG, "flutter patch is loaded successfully");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这一块有计划修复么?

1.17源码 1.22.4源码

已经修复了

Notzuonotdied commented 3 years ago

@heroghost 我上面发的“--AOT_SHARED_LIBRARY_NAME=“是可以通过ensureInitializationComplete的args传递进来的。

原因就在:

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.
shellArgs.add(
    "--"
        + AOT_SHARED_LIBRARY_NAME
        + "="
        + applicationInfo.nativeLibraryDir
        + File.separator
        + aotSharedLibraryName);    

上面的代码里面:shellArgs传递了两次--AOT_SHARED_LIBRARY_NAME参数。

这里我们可以得出一个猜想:Flutter Engine在遇到传入多次--AOT_SHARED_LIBRARY_NAME参数的时候,会通过循环的形式去判断哪一个路径可以load。(这一块我也验证过了,可以实现动态替换)

因此,可以得出如下结论:

想要替换,只需要将app.so的路径通过args数组,将“--AOT_SHARED_LIBRARY_NAME=<你的libapp.so的路径>”参数传递进来就可以实现动态替换了。

所以这一块不需要走反射了。

magicbaby810 commented 3 years ago

@heroghost 我上面发的“--AOT_SHARED_LIBRARY_NAME=“是可以通过ensureInitializationComplete的args传递进来的。

原因就在:

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.
shellArgs.add(
    "--"
        + AOT_SHARED_LIBRARY_NAME
        + "="
        + applicationInfo.nativeLibraryDir
        + File.separator
        + aotSharedLibraryName);    

上面的代码里面:shellArgs传递了两次--AOT_SHARED_LIBRARY_NAME参数。

这里我们可以得出一个猜想:Flutter Engine在遇到传入多次--AOT_SHARED_LIBRARY_NAME参数的时候,会通过循环的形式去判断哪一个路径可以load。(这一块我也验证过了,可以实现动态替换)

因此,可以得出如下结论:

想要替换,只需要将app.so的路径通过args数组,将“--AOT_SHARED_LIBRARY_NAME=<你的libapp.so的路径>”参数传递进来就可以实现动态替换了。

所以这一块不需要走反射了。

是的,源码里so路径还可以通过metadata配置

Notzuonotdied commented 3 years ago

赞!那我先把这个issue关闭了