Skip to content

Instantly share code, notes, and snippets.

@wei-spring
Created August 5, 2020 02:05
Show Gist options
  • Save wei-spring/e0f0586de07507337360b82f9e83dfa4 to your computer and use it in GitHub Desktop.
Save wei-spring/e0f0586de07507337360b82f9e83dfa4 to your computer and use it in GitHub Desktop.
Tinker for Flutter with FlutterBoost
package com.idlefish.flutterboost;
import android.app.Activity;
import android.app.Application;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.util.Log;
import com.idlefish.flutterboost.interfaces.*;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.loader.FlutterLoader;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.view.FlutterMain;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
public class FlutterBoost {
private Platform mPlatform;
private FlutterViewContainerManager mManager;
private FlutterEngine mEngine;
private Activity mCurrentActiveActivity;
private boolean mEnterActivityCreate = false;
static FlutterBoost sInstance = null;
private static boolean sInit;
private long FlutterPostFrameCallTime = 0;
private Application.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;
private PluginRegistry mRegistry;
public long getFlutterPostFrameCallTime() {
return FlutterPostFrameCallTime;
}
private String libPath;
public void setFlutterPostFrameCallTime(long FlutterPostFrameCallTime) {
this.FlutterPostFrameCallTime = FlutterPostFrameCallTime;
}
public static FlutterBoost instance() {
if (sInstance == null) {
sInstance = new FlutterBoost();
}
return sInstance;
}
public void init(Platform platform, final String libName) {
if (sInit) {
Debuger.log("FlutterBoost is alread inited. Do not init twice");
return;
}
libPath = libName;
mPlatform = platform;
mManager = new FlutterViewContainerManager();
mActivityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//fix crash:'FlutterBoostPlugin not register yet'
//case: initFlutter after Activity.OnCreate method,and then called start/stop crash
// In SplashActivity ,showDialog(in OnCreate method) to check permission, if authorized, then init sdk and jump homePage)
mEnterActivityCreate = true;
mCurrentActiveActivity = activity;
if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) {
doInitialFlutter();
}
}
@Override
public void onActivityStarted(Activity activity) {
if (!mEnterActivityCreate) {
return;
}
if (mCurrentActiveActivity == null) {
Debuger.log("Application entry foreground");
if (mEngine != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "foreground");
channel().sendEvent("lifecycle", map);
}
}
mCurrentActiveActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
if (!mEnterActivityCreate) {
return;
}
mCurrentActiveActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
if (!mEnterActivityCreate) {
return;
}
}
@Override
public void onActivityStopped(Activity activity) {
if (!mEnterActivityCreate) {
return;
}
if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background");
if (mEngine != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "background");
channel().sendEvent("lifecycle", map);
}
mCurrentActiveActivity = null;
}
}
@Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
if (!mEnterActivityCreate) {
return;
}
}
@Override
public void onActivityDestroyed(Activity activity) {
if (!mEnterActivityCreate) {
return;
}
if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background");
if (mEngine != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "background");
channel().sendEvent("lifecycle", map);
}
mCurrentActiveActivity = null;
}
}
};
platform.getApplication().registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
if (mPlatform.whenEngineStart() == ConfigBuilder.IMMEDIATELY) {
doInitialFlutter();
}
sInit = true;
}
public void doInitialFlutter() {
if (mEngine != null) {
return;
}
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.beforeCreateEngine();
}
FlutterEngine flutterEngine = createEngine();
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.onEngineCreated();
}
if (flutterEngine.getDartExecutor().isExecutingDart()) {
return;
}
if (mPlatform.initialRoute() != null) {
flutterEngine.getNavigationChannel().setInitialRoute(mPlatform.initialRoute());
}
DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(),
"main"
);
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
}
public static class ConfigBuilder {
public static final String DEFAULT_DART_ENTRYPOINT = "main";
public static final String DEFAULT_INITIAL_ROUTE = "/";
public static int IMMEDIATELY = 0; //立即启动引擎
public static int ANY_ACTIVITY_CREATED = 1; //当有任何Activity创建时,启动引擎
public static int FLUTTER_ACTIVITY_CREATED = 2; //当有flutterActivity创建时,启动引擎
public static int APP_EXit = 0; //所有flutter Activity destory 时,销毁engine
public static int All_FLUTTER_ACTIVITY_DESTROY = 1; //所有flutter Activity destory 时,销毁engine
private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT;
private String initialRoute = DEFAULT_INITIAL_ROUTE;
private int whenEngineStart = ANY_ACTIVITY_CREATED;
private int whenEngineDestory = APP_EXit;
private boolean isDebug = false;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.texture;
private Application mApp;
private INativeRouter router = null;
private BoostLifecycleListener lifecycleListener;
public ConfigBuilder(Application app, INativeRouter router) {
this.router = router;
this.mApp = app;
}
public ConfigBuilder renderMode(FlutterView.RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
public ConfigBuilder dartEntrypoint(@NonNull String dartEntrypoint) {
this.dartEntrypoint = dartEntrypoint;
return this;
}
public ConfigBuilder initialRoute(@NonNull String initialRoute) {
this.initialRoute = initialRoute;
return this;
}
public ConfigBuilder isDebug(boolean isDebug) {
this.isDebug = isDebug;
return this;
}
public ConfigBuilder whenEngineStart(int whenEngineStart) {
this.whenEngineStart = whenEngineStart;
return this;
}
public ConfigBuilder lifecycleListener(BoostLifecycleListener lifecycleListener) {
this.lifecycleListener = lifecycleListener;
return this;
}
public Platform build() {
Platform platform = new Platform() {
public Application getApplication() {
return ConfigBuilder.this.mApp;
}
public boolean isDebug() {
return ConfigBuilder.this.isDebug;
}
@Override
public String initialRoute() {
return ConfigBuilder.this.initialRoute;
}
public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
router.openContainer(context, url, urlParams, requestCode, exts);
}
public int whenEngineStart() {
return ConfigBuilder.this.whenEngineStart;
}
public FlutterView.RenderMode renderMode() {
return ConfigBuilder.this.renderMode;
}
};
platform.lifecycleListener = this.lifecycleListener;
return platform;
}
}
public IContainerManager containerManager() {
return sInstance.mManager;
}
public Platform platform() {
return sInstance.mPlatform;
}
public FlutterBoostPlugin channel() {
return FlutterBoostPlugin.singleton();
}
public Activity currentActivity() {
return sInstance.mCurrentActiveActivity;
}
public IFlutterViewContainer findContainerById(String id) {
return mManager.findContainerById(id);
}
private FlutterEngine createEngine() {
System.err.println("aaa flutter libpath:" + libPath);
if (mEngine == null) {
FlutterMain.startInitialization(mPlatform.getApplication());
try {
if (!"libapp.so".equals(libPath) && libPath != null && !libPath.equals("null")) {
FlutterLoader flutterLoader = FlutterLoader.getInstance();
Log.e("FlutterPatch", "flutterPatchInit() called init after " + libPath);
Field field = FlutterLoader.class.getDeclaredField("aotSharedLibraryName");
field.setAccessible(true);
field.set(flutterLoader, libPath);
}
} catch (Exception e) {
e.printStackTrace();
}
FlutterShellArgs flutterShellArgs = new FlutterShellArgs(new String[0]);
FlutterMain.ensureInitializationComplete(
mPlatform.getApplication().getApplicationContext(), flutterShellArgs.toArray());
mEngine = new FlutterEngine(mPlatform.getApplication().getApplicationContext(), FlutterLoader.getInstance(), new FlutterJNI(), null, true);
registerPlugins(mEngine);
// mRegistry = new BoostPluginRegistry(createEngine());
// mPlatform.registerPlugins(mRegistry);
}
return mEngine;
}
private void registerPlugins(FlutterEngine engine) {
try {
Class<?> generatedPluginRegistrant = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method registrationMethod = generatedPluginRegistrant.getDeclaredMethod("registerWith", FlutterEngine.class);
registrationMethod.invoke(null, engine);
} catch (Exception e) {
Debuger.exception(e);
}
}
public FlutterEngine engineProvider() {
return mEngine;
}
public void boostDestroy() {
if (mEngine != null) {
mEngine.destroy();
}
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.onEngineDestroy();
}
mEngine = null;
mCurrentActiveActivity = null;
}
public interface BoostLifecycleListener {
void beforeCreateEngine();
void onEngineCreated();
void onPluginsRegistered();
void onEngineDestroy();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment