現有Android專案中整合Flutter/Flutter混合開發實戰(二):FlutterActivity原始碼分析

立新街甲一號發表於2019-02-27

二.整合Flutter

2.通過繼承FlutterActivity等元件整合

需要說明的是,我最後在通過route新增不同flutter介面的地方失敗了,目前沒有找到好的解決辦法,如果有人研究過這個,希望可以指出我的錯誤,幫我解決。

第一篇文章中詳細介紹瞭如何將FlutterView新增到Android原生頁面佈局中。

(PS:有小夥伴在評論裡說,可以設定監聽來達到原生控制元件和FlutterView同時載入的效果,的確是一個可以優化的點,謝謝您的幫助!)

第二種方式是通過繼承FlutterActivity、FlutterFragment及FlutterFragmentActivity。

public class FlutterExtendActivity extends FlutterActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
    }
}複製程式碼

但是目前有個問題沒有解決,是這樣的:

這樣建立的Activity中的Flutter介面是default值,也就是空值返回的介面,但我們不可能永遠通過預設的initialRoute來新增FlutterView。

如果在FlutterActivity的onCreate中更改route值呢?

 @Override
    protected void onCreate(Bundle savedInstanceState) {
        FlutterMain.startInitialization(getApplicationContext());
        super.onCreate(savedInstanceState);
        getFlutterView().setInitialRoute("flutter_activity");
複製程式碼

失敗了。

現有Android專案中整合Flutter/Flutter混合開發實戰(二):FlutterActivity原始碼分析

getFlutterView().pushRoute("flutter_activity");
複製程式碼

也失敗了。

現有Android專案中整合Flutter/Flutter混合開發實戰(二):FlutterActivity原始碼分析

--------------------------------------------------------------------

↑這兩張圖其實是同一張...反正都不成功

主要原因是,super.onCreate之後,FlutterActivity已經建立好了佈局,而且我們的這個Activity中又沒有setContentView()的實現,設定route的操作不能挪到super.onCreate()前面。


我檢視了FlutterActivity的原始碼,這個問題目前還沒有解決,如果各位小夥伴有解決方法希望不吝賜教.

public class FlutterActivity extends Activity implements Provider, PluginRegistry, ViewFactory {
    private static final String TAG = "FlutterActivity";
    private final FlutterActivityDelegate delegate = new FlutterActivityDelegate(this, this);
    private final FlutterActivityEvents eventDelegate;
    private final Provider viewProvider;
    private final PluginRegistry pluginRegistry;

    public FlutterActivity() {
        this.eventDelegate = this.delegate;
        this.viewProvider = this.delegate;
        this.pluginRegistry = this.delegate;
    }

    public FlutterView getFlutterView() {
        return this.viewProvider.getFlutterView();
    }

    public FlutterView createFlutterView(Context context) {
        return null;
    }

    public FlutterNativeView createFlutterNativeView() {
        return null;
    }

    public boolean retainFlutterNativeView() {
        return false;
    }
}複製程式碼

可以看出FlutterActivity實際是繼承了Activity,實現了FlutterView.Provider、

PluginRegistry、ViewFactory三個介面。

但是FlutterActivity的三個在例項化時候的變數都指向了一個FlutterActivityDelegate物件,也就是說,它代理了FlutterActivity幾乎所有的動作。

三個介面大致內容如下:

(1).FlutterView.Provider

public interface Provider {
    FlutterView getFlutterView();
}複製程式碼

FlutterView.Provider是一個介面,提供了getFlutterView()抽象方法

那麼FlutterActivity的具體實現呢?

public FlutterView getFlutterView() {
    return this.viewProvider.getFlutterView();
}複製程式碼

但是viewProvider又指向了這個FlutterActivityDelegate;

(2).PluginRegistry

public interface PluginRegistry {
    PluginRegistry.Registrar registrarFor(String var1);

    boolean hasPlugin(String var1);

    <T> T valuePublishedByPlugin(String var1);

    public interface PluginRegistrantCallback {
        void registerWith(PluginRegistry var1);
    }

    public interface ViewDestroyListener {
        boolean onViewDestroy(FlutterNativeView var1);
    }

    public interface UserLeaveHintListener {
        void onUserLeaveHint();
    }

    public interface NewIntentListener {
        boolean onNewIntent(Intent var1);
    }

    public interface ActivityResultListener {
        boolean onActivityResult(int var1, int var2, Intent var3);
    }

    public interface RequestPermissionsResultListener {
        boolean onRequestPermissionsResult(int var1, String[] var2, int[] var3);
    }
}複製程式碼

(3).ViewFactory

public interface ViewFactory {
    FlutterView createFlutterView(Context var1);

    FlutterNativeView createFlutterNativeView();

    boolean retainFlutterNativeView();
}複製程式碼

具體實現:

public FlutterView createFlutterView(Context context) {
    return null;
}
public FlutterNativeView createFlutterNativeView() {
    return null;
}
public boolean retainFlutterNativeView() {
    return false;
}複製程式碼

也就是...這個介面的實現基本沒有什麼意義.

所以我們還是要看FlutterActivityDelegate這個類和它的例項究竟做了什麼.

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    this.eventDelegate.onCreate(savedInstanceState);
}複製程式碼

呼叫了eventDelegate.onCreate(),我們可以順藤摸瓜看看它的onCreate()

public void onCreate(Bundle savedInstanceState) {
    if (VERSION.SDK_INT >= 21) {
        Window window = this.activity.getWindow();
        window.addFlags(-2147483648);
        window.setStatusBarColor(1073741824);
        window.getDecorView().setSystemUiVisibility(1280);
    }

    String[] args = getArgsFromIntent(this.activity.getIntent());
    FlutterMain.ensureInitializationComplete(this.activity.getApplicationContext(), args);
    this.flutterView = this.viewFactory.createFlutterView(this.activity);
    if (this.flutterView == null) {
        FlutterNativeView nativeView = this.viewFactory.createFlutterNativeView();
        this.flutterView = new FlutterView(this.activity, (AttributeSet)null, nativeView);
        this.flutterView.setLayoutParams(matchParent);
        this.activity.setContentView(this.flutterView);
        this.launchView = this.createLaunchView();
        if (this.launchView != null) {
            this.addLaunchView();
        }
    }

    if (!this.loadIntent(this.activity.getIntent())) {
        String appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
        if (appBundlePath != null) {
            this.runBundle(appBundlePath);
        }

    }
}複製程式碼

FlutterView是由FlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) 這個構造方法new出來的。

實際上,

@NonNull
public static FlutterView createView(@NonNull final Activity activity, @NonNull final Lifecycle lifecycle, final String initialRoute) {
  FlutterMain.startInitialization(activity.getApplicationContext());
  FlutterMain.ensureInitializationComplete(activity.getApplicationContext(), null);
  final FlutterNativeView nativeView = new FlutterNativeView(activity);
  //↓這裡還是呼叫了FlutterView的三個引數構造
  final FlutterView flutterView = new FlutterView(activity, null, nativeView) {
    private final BasicMessageChannel<String> lifecycleMessages = new BasicMessageChannel<>(this, "flutter/lifecycle", StringCodec.INSTANCE);
    @Override
    public void onFirstFrame() {
      super.onFirstFrame();
      setAlpha(1.0f);
    }
}複製程式碼

現有Android專案中整合Flutter/Flutter混合開發實戰(二):FlutterActivity原始碼分析

我們之前使用的Flutter.createView()顯然也是呼叫了這個構造。但是createView()有一個String型別的initialRoute引數,FlutterActivity中呼叫的構造則沒有。我猜想,會不會提供了更改Route的方式呢?

private boolean loadIntent(Intent intent) {
    String action = intent.getAction();
    if ("android.intent.action.RUN".equals(action)) {
        String route = intent.getStringExtra("route");
        //獲取Intent中傳遞的route
        String appBundlePath = intent.getDataString();
        if (appBundlePath == null) {
            appBundlePath = FlutterMain.findAppBundlePath(this.activity.getApplicationContext());
        }

        if (route != null) {
            this.flutterView.setInitialRoute(route);
        }
        //如果route值不為空,則將它設定給flutterview

        this.runBundle(appBundlePath);
        return true;
    } else {
        return false;
    }
}複製程式碼

FlutterActivityDelegate中有這個方法,從這個Activity跳轉過來的Intent中可以獲取route,key值為"route",如果route不為空的話,就給這個FlutterView設定一個initialRoute。出於這樣的思路,我在跳轉本Activity的時候,傳遞一個在Flutter中定義好頁面的route值進去怎麼樣?

做了一下嘗試,

findViewById(R.id.btn_flutter_acty).setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        startActivity(new Intent(MainActivity.this, FlutterExtendActivity.class).putExtra("route","flutter1"));
    }
});複製程式碼

結果是失敗了,跳轉後頁面上出現的FlutterView仍然是傳default時返回的頁面.

現有Android專案中整合Flutter/Flutter混合開發實戰(二):FlutterActivity原始碼分析

額,由於今天沒有什麼時間了,所以就寫這麼多。確實人菜話多,而且今天也沒有什麼進展(MethodChannel實現通訊成功了,不過明天再寫吧)今天就卡在了這個FlutterActivity上,不知道明天能找到什麼解決辦法...請大家見諒。



相關文章