Commit 6afc509d authored by yangwu.jia's avatar yangwu.jia

1.9版本升级

parent d9ac3683
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost;
import android.content.Context;
import com.idlefish.flutterboost.interfaces.IFlutterEngineProvider;
import com.idlefish.flutterboost.interfaces.IStateListener;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.view.FlutterMain;
public class BoostEngineProvider implements IFlutterEngineProvider {
private FlutterEngine mEngine = null;
public BoostEngineProvider() {}
@Override
public BoostFlutterEngine createEngine(Context context) {
return new BoostFlutterEngine(context.getApplicationContext());
}
@Override
public FlutterEngine provideEngine(Context context) {
Utils.assertCallOnMainThread();
if (mEngine == null) {
FlutterShellArgs flutterShellArgs = new FlutterShellArgs(new String[0]);
FlutterMain.ensureInitializationComplete(
context.getApplicationContext(), flutterShellArgs.toArray());
mEngine = new FlutterEngine(context.getApplicationContext());
// final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
// if(stateListener != null) {
// stateListener.onEngineCreated(mEngine);
// }
}
return mEngine;
}
@Override
public FlutterEngine tryGetEngine() {
return mEngine;
}
public static void assertEngineRunning(){
final FlutterEngine engine = NewFlutterBoost.instance().engineProvider().tryGetEngine();
// if(engine == null || !engine.isRunning()) {
// throw new RuntimeException("engine is not running yet!");
// }
}
}
package com.idlefish.flutterboost;
import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.view.Surface;
import android.view.View;
import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IStateListener;
import java.lang.ref.WeakReference;
import java.lang.reflect.Field;
import java.nio.ByteBuffer;
import io.flutter.app.FlutterPluginRegistry;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterJNI;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.embedding.engine.renderer.FlutterRenderer;
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.editing.TextInputPlugin;
import io.flutter.plugin.platform.PlatformViewRegistry;
import io.flutter.view.FlutterMain;
import io.flutter.view.FlutterView;
import io.flutter.view.TextureRegistry;
public class BoostFlutterEngine extends FlutterEngine {
protected WeakReference<Activity> mCurrentActivityRef;
public BoostFlutterEngine(@NonNull Context context) {
super(context);
}
// public BoostFlutterEngine(@NonNull Context context, DartExecutor.DartEntrypoint entrypoint, String initRoute) {
// super(context);
// mContext = context.getApplicationContext();
//// mBoostPluginRegistry = new BoostPluginRegistry(this, context);
//
// if (entrypoint != null) {
// mEntrypoint = entrypoint;
// } else {
// mEntrypoint = defaultDartEntrypoint(context);
// }
//
// if (initRoute != null) {
// mInitRoute = initRoute;
// } else {
// mInitRoute = defaultInitialRoute(context);
// }
//
// FlutterJNI flutterJNI = null;
// try {
// Field field = FlutterEngine.class.getDeclaredField("flutterJNI");
// field.setAccessible(true);
//
// flutterJNI = (FlutterJNI) field.get(this);
// } catch (Throwable t) {
// try {
// for(Field field:FlutterEngine.class.getDeclaredFields()) {
// field.setAccessible(true);
// Object o = field.get(this);
//
// if(o instanceof FlutterJNI) {
// flutterJNI = (FlutterJNI)o;
// }
// }
//
// if(flutterJNI == null) {
// throw new RuntimeException("FlutterJNI not found");
// }
// }catch (Throwable it){
// Debuger.exception(it);
// }
// }
// mFakeRender = new FakeRender(flutterJNI);
// }
// public void startRun(@Nullable Activity activity) {
// mCurrentActivityRef = new WeakReference<>(activity);
//
// if (!getDartExecutor().isExecutingDart()) {
//
// Debuger.log("engine start running...");
//
// getNavigationChannel().setInitialRoute(mInitRoute);
// getDartExecutor().executeDartEntrypoint(mEntrypoint);
//
// final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
// if (stateListener != null) {
// stateListener.onEngineStarted(this);
// }
//
//// FlutterBoost.singleton().platform().registerPlugins(mBoostPluginRegistry);
//
// if(activity != null) {
// FlutterRenderer.ViewportMetrics metrics = new FlutterRenderer.ViewportMetrics();
// metrics.devicePixelRatio = activity.getResources().getDisplayMetrics().density;
// final View decor = activity.getWindow().getDecorView();
// if(decor != null) {
// metrics.width = decor.getWidth();
// metrics.height = decor.getHeight();
// }
//
// if (metrics.width <= 0 || metrics.height <= 0) {
// metrics.width = Utils.getMetricsWidth(activity);
// metrics.height = Utils.getMetricsHeight(activity);
// }
//
// metrics.paddingTop = Utils.getStatusBarHeight(activity);
// metrics.paddingRight = 0;
// metrics.paddingBottom = 0;
// metrics.paddingLeft = 0;
// metrics.viewInsetTop = 0;
// metrics.viewInsetRight = 0;
// metrics.viewInsetBottom = 0;
// metrics.viewInsetLeft = 0;
//
// getRenderer().setViewportMetrics(metrics);
// }
// }
// }
protected DartExecutor.DartEntrypoint defaultDartEntrypoint(Context context) {
return DartExecutor.DartEntrypoint.createDefault();
}
protected String defaultInitialRoute(Context context) {
return "/";
}
// public BoostPluginRegistry getBoostPluginRegistry() {
// return mBoostPluginRegistry;
// }
public boolean isRunning() {
return getDartExecutor().isExecutingDart();
}
@NonNull
@Override
public FlutterRenderer getRenderer() {
StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
boolean hit = false;
for (StackTraceElement st : stackTrace) {
if (st.getMethodName().equals("sendViewportMetricsToFlutter")) {
hit = true;
break;
}
}
if (hit) {
return null;
} else {
return super.getRenderer();
}
}
public class BoostPluginRegistry extends FlutterPluginRegistry {
private FlutterEngine mEngine;
public BoostPluginRegistry(FlutterEngine engine, Context context) {
super(engine, context);
mEngine = engine;
}
public PluginRegistry.Registrar registrarFor(String pluginKey) {
return new BoostRegistrar(mEngine, super.registrarFor(pluginKey));
}
}
public class BoostRegistrar implements PluginRegistry.Registrar {
private final PluginRegistry.Registrar mRegistrar;
private final FlutterEngine mEngine;
BoostRegistrar(FlutterEngine engine, PluginRegistry.Registrar registrar) {
mRegistrar = registrar;
mEngine = engine;
}
@Override
public Activity activity() {
Activity activity;
IContainerRecord record;
record = FlutterBoost.singleton().containerManager().getCurrentTopRecord();
if (record == null) {
record = FlutterBoost.singleton().containerManager().getLastGenerateRecord();
}
if (record == null) {
activity = FlutterBoost.singleton().currentActivity();
} else {
activity = record.getContainer().getContextActivity();
}
if (activity == null && mCurrentActivityRef != null) {
activity = mCurrentActivityRef.get();
}
if (activity == null) {
throw new RuntimeException("current has no valid Activity yet");
}
return activity;
}
@Override
public Context context() {
return mRegistrar.context();
}
@Override
public Context activeContext() {
return mRegistrar.activeContext();
}
@Override
public BinaryMessenger messenger() {
return mEngine.getDartExecutor();
}
@Override
public TextureRegistry textures() {
return mEngine.getRenderer();
}
@Override
public PlatformViewRegistry platformViewRegistry() {
return mRegistrar.platformViewRegistry();
}
@Override
public FlutterView view() {
throw new RuntimeException("should not use!!!");
}
@Override
public String lookupKeyForAsset(String s) {
return mRegistrar.lookupKeyForAsset(s);
}
@Override
public String lookupKeyForAsset(String s, String s1) {
return mRegistrar.lookupKeyForAsset(s, s1);
}
@Override
public PluginRegistry.Registrar publish(Object o) {
return mRegistrar.publish(o);
}
@Override
public PluginRegistry.Registrar addRequestPermissionsResultListener(PluginRegistry.RequestPermissionsResultListener requestPermissionsResultListener) {
return mRegistrar.addRequestPermissionsResultListener(requestPermissionsResultListener);
}
@Override
public PluginRegistry.Registrar addActivityResultListener(PluginRegistry.ActivityResultListener activityResultListener) {
return mRegistrar.addActivityResultListener(activityResultListener);
}
@Override
public PluginRegistry.Registrar addNewIntentListener(PluginRegistry.NewIntentListener newIntentListener) {
return mRegistrar.addNewIntentListener(newIntentListener);
}
@Override
public PluginRegistry.Registrar addUserLeaveHintListener(PluginRegistry.UserLeaveHintListener userLeaveHintListener) {
return mRegistrar.addUserLeaveHintListener(userLeaveHintListener);
}
@Override
public PluginRegistry.Registrar addViewDestroyListener(PluginRegistry.ViewDestroyListener viewDestroyListener) {
return mRegistrar.addViewDestroyListener(viewDestroyListener);
}
}
private boolean viewportMetricsEqual(FlutterRenderer.ViewportMetrics a, FlutterRenderer.ViewportMetrics b) {
return a != null && b != null &&
a.height == b.height &&
a.width == b.width &&
a.devicePixelRatio == b.devicePixelRatio &&
a.paddingBottom == b.paddingBottom &&
a.paddingLeft == b.paddingLeft &&
a.paddingRight == b.paddingRight &&
a.paddingTop == b.paddingTop &&
a.viewInsetLeft == b.viewInsetLeft &&
a.viewInsetRight == b.viewInsetRight &&
a.viewInsetTop == b.viewInsetTop &&
a.viewInsetBottom == b.viewInsetBottom;
}
class FakeRender extends FlutterRenderer {
private ViewportMetrics last;
public FakeRender(FlutterJNI flutterJNI) {
super(flutterJNI);
}
@Override
public void setViewportMetrics(@NonNull ViewportMetrics viewportMetrics) {
if (viewportMetrics.width > 0 && viewportMetrics.height > 0 /*&& !viewportMetricsEqual(last, viewportMetrics)*/) {
last = viewportMetrics;
Debuger.log("setViewportMetrics w:" + viewportMetrics.width + " h:" + viewportMetrics.height);
super.setViewportMetrics(viewportMetrics);
}
}
@Override
public void attachToRenderSurface(@NonNull RenderSurface renderSurface) {
Debuger.exception("should never called!");
}
@Override
public void detachFromRenderSurface() {
Debuger.exception("should never called!");
}
@Override
public void addOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
Debuger.exception("should never called!");
}
@Override
public void removeOnFirstFrameRenderedListener(@NonNull OnFirstFrameRenderedListener listener) {
Debuger.exception("should never called!");
}
@Override
public SurfaceTextureEntry createSurfaceTexture() {
Debuger.exception("should never called!");
return null;
}
@Override
public void surfaceCreated(Surface surface) {
Debuger.exception("should never called!");
}
@Override
public void surfaceChanged(int width, int height) {
Debuger.exception("should never called!");
}
@Override
public void surfaceDestroyed() {
Debuger.exception("should never called!");
}
@Override
public Bitmap getBitmap() {
Debuger.exception("should never called!");
return null;
}
@Override
public void dispatchPointerDataPacket(ByteBuffer buffer, int position) {
Debuger.exception("should never called!");
}
@Override
public boolean isSoftwareRenderingEnabled() {
Debuger.exception("should never called!");
return false;
}
@Override
public void setAccessibilityFeatures(int flags) {
Debuger.exception("should never called!");
}
@Override
public void setSemanticsEnabled(boolean enabled) {
Debuger.exception("should never called!");
}
@Override
public void dispatchSemanticsAction(int id, int action, ByteBuffer args, int argsPosition) {
Debuger.exception("should never called!");
}
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v4.view.ViewCompat;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.accessibility.AccessibilityNodeProvider;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.idlefish.flutterboost.interfaces.IStateListener;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.List;
import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.view.AccessibilityBridge;
public class BoostFlutterView extends FrameLayout {
private BoostFlutterEngine mFlutterEngine;
private XFlutterView mFlutterView;
private PlatformPlugin mPlatformPlugin;
private Bundle mArguments;
private RenderingProgressCoverCreator mRenderingProgressCoverCreator;
private View mRenderingProgressCover;
private final List<OnFirstFrameRenderedListener> mFirstFrameRenderedListeners = new LinkedList<>();
private boolean mEngineAttached = false;
private boolean mNeedSnapshotWhenDetach = false;
private SnapshotView mSnapshot;
private final io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener mOnFirstFrameRenderedListener =
new io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener() {
@Override
public void onFirstFrameRendered() {
Debuger.log("BoostFlutterView onFirstFrameRendered");
if(mRenderingProgressCover != null && mRenderingProgressCover.getParent() != null) {
((ViewGroup)mRenderingProgressCover.getParent()).removeView(mRenderingProgressCover);
}
if(mNeedSnapshotWhenDetach) {
mSnapshot.dismissSnapshot(BoostFlutterView.this);
}
final Object[] listeners = mFirstFrameRenderedListeners.toArray();
for (Object obj : listeners) {
((OnFirstFrameRenderedListener) obj).onFirstFrameRendered(BoostFlutterView.this);
}
}
};
private final ViewTreeObserver.OnGlobalLayoutListener mGlobalLayoutListener = new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
ViewCompat.requestApplyInsets(mFlutterView);
}
};
public BoostFlutterView(Context context, BoostFlutterEngine engine, Bundle args, RenderingProgressCoverCreator creator) {
super(context);
mFlutterEngine = engine;
mArguments = args;
mRenderingProgressCoverCreator = creator;
init();
}
private void init() {
if (mFlutterEngine == null) {
mFlutterEngine = createFlutterEngine(getContext());
}
if (mArguments == null) {
mArguments = new Bundle();
}
mPlatformPlugin = new PlatformPlugin((Activity) getContext(), mFlutterEngine.getPlatformChannel());
mFlutterView = new XFlutterView(getContext(), getRenderMode(), getTransparencyMode());
addView(mFlutterView, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
mSnapshot = new SnapshotView(getContext());
if(mRenderingProgressCoverCreator != null) {
mRenderingProgressCover = mRenderingProgressCoverCreator
.createRenderingProgressCover(getContext());
}else{
mRenderingProgressCover = createRenderingProgressCorver();
}
if(mRenderingProgressCover != null) {
addView(mRenderingProgressCover, new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
}
mFlutterView.addOnFirstFrameRenderedListener(mOnFirstFrameRenderedListener);
// mFlutterEngine.startRun((Activity)getContext());
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if(stateListener != null) {
stateListener.onFlutterViewInited(mFlutterEngine,this);
}
checkAssert();
}
private void checkAssert(){
try {
Method method = FlutterView.class.getDeclaredMethod("sendViewportMetricsToFlutter");
if(method == null) {
throw new Exception("method: FlutterView.sendViewportMetricsToFlutter not found!");
}
}catch (Throwable t){
Debuger.exception(t);
}
}
protected View createRenderingProgressCorver(){
FrameLayout frameLayout = new FrameLayout(getContext());
frameLayout.setBackgroundColor(Color.WHITE);
LinearLayout linearLayout = new LinearLayout(getContext());
linearLayout.setOrientation(LinearLayout.VERTICAL);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
frameLayout.addView(linearLayout,layoutParams);
ProgressBar progressBar = new ProgressBar(getContext());
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
linearLayout.addView(progressBar,params);
TextView textView = new TextView(getContext());
params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setText("Frame Rendering...");
linearLayout.addView(textView,params);
return frameLayout;
}
protected BoostFlutterEngine createFlutterEngine(Context context) {
// return FlutterBoost.singleton().engineProvider().provideEngine(context);
return null;
}
public void addFirstFrameRendered(OnFirstFrameRenderedListener listener) {
mFirstFrameRenderedListeners.add(listener);
}
public void removeFirstFrameRendered(OnFirstFrameRenderedListener listener) {
mFirstFrameRenderedListeners.remove(listener);
}
protected FlutterView.RenderMode getRenderMode() {
String renderModeName = mArguments.getString("flutterview_render_mode", FlutterView.RenderMode.surface.name());
return FlutterView.RenderMode.valueOf(renderModeName);
}
protected FlutterView.TransparencyMode getTransparencyMode() {
String transparencyModeName = mArguments.getString("flutterview_transparency_mode", FlutterView.TransparencyMode.transparent.name());
return FlutterView.TransparencyMode.valueOf(transparencyModeName);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
ViewCompat.requestApplyInsets(this);
getViewTreeObserver().addOnGlobalLayoutListener(mGlobalLayoutListener);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
getViewTreeObserver().removeOnGlobalLayoutListener(mGlobalLayoutListener);
onDetach();
}
public BoostFlutterEngine getEngine(){
return mFlutterEngine;
}
public void onResume() {
Debuger.log("BoostFlutterView onResume");
// mFlutterEngine.getLifecycleChannel().appIsResumed();
}
// public void onPostResume() {
// Debuger.log("BoostFlutterView onPostResume");
// mPlatformPlugin.onPostResume();
// }
public void onPause() {
Debuger.log("BoostFlutterView onPause");
// mFlutterEngine.getLifecycleChannel().appIsInactive();
}
public void onStop() {
Debuger.log("BoostFlutterView onStop");
// mFlutterEngine.getLifecycleChannel().appIsPaused();
}
public void onAttach() {
Debuger.log("BoostFlutterView onAttach");
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if(stateListener != null) {
stateListener.beforeEngineAttach(mFlutterEngine,this);
}
mFlutterView.attachToFlutterEngine(mFlutterEngine);
mEngineAttached = true;
if(stateListener != null) {
stateListener.afterEngineAttached(mFlutterEngine,this);
}
}
public void toggleSnapshot() {
mSnapshot.toggleSnapshot(this);
}
public void toggleAttach() {
if(mEngineAttached) {
onDetach();
}else{
onAttach();
}
}
public void onDetach() {
Debuger.log("BoostFlutterView onDetach");
if(mNeedSnapshotWhenDetach) {
mSnapshot.showSnapshot(BoostFlutterView.this);
}
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if(stateListener != null) {
stateListener.beforeEngineDetach(mFlutterEngine,this);
}
mFlutterView.detachFromFlutterEngine();
mEngineAttached = false;
if(stateListener != null) {
stateListener.afterEngineDetached(mFlutterEngine,this);
}
}
public void onDestroy() {
Debuger.log("BoostFlutterView onDestroy");
mFlutterView.removeOnFirstFrameRenderedListener(mOnFirstFrameRenderedListener);
mFlutterView.release();
}
//混合栈的返回和原来Flutter的返回逻辑不同
public void onBackPressed() {
// Debuger.log("onBackPressed()");
// if (mFlutterEngine != null) {
// mFlutterEngine.getNavigationChannel().popRoute();
// } else {
// Debuger.log("Invoked onBackPressed() before BoostFlutterView was attached to an Activity.");
// }
}
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if (mFlutterEngine != null) {
// mFlutterEngine.getPluginRegistry().onRequestPermissionsResult(requestCode, permissions, grantResults);
} else {
Debuger.log("onRequestPermissionResult() invoked before BoostFlutterView was attached to an Activity.");
}
}
public void onNewIntent(Intent intent) {
if (mFlutterEngine != null) {
// mFlutterEngine.getPluginRegistry().onNewIntent(intent);
} else {
Debuger.log("onNewIntent() invoked before BoostFlutterView was attached to an Activity.");
}
}
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (mFlutterEngine != null) {
// mFlutterEngine.getPluginRegistry().onActivityResult(requestCode, resultCode, data);
} else {
Debuger.log("onActivityResult() invoked before BoostFlutterView was attached to an Activity.");
}
}
public void onUserLeaveHint() {
if (mFlutterEngine != null) {
// mFlutterEngine.getPluginRegistry().onUserLeaveHint();
} else {
Debuger.log("onUserLeaveHint() invoked before BoostFlutterView was attached to an Activity.");
}
}
public void onTrimMemory(int level) {
if (mFlutterEngine != null) {
if (level == 10) {
mFlutterEngine.getSystemChannel().sendMemoryPressureWarning();
}
} else {
Debuger.log("onTrimMemory() invoked before BoostFlutterView was attached to an Activity.");
}
}
public void onLowMemory() {
mFlutterEngine.getSystemChannel().sendMemoryPressureWarning();
}
public static class Builder {
private Context context;
private BoostFlutterEngine engine;
private FlutterView.RenderMode renderMode;
private FlutterView.TransparencyMode transparencyMode;
private RenderingProgressCoverCreator renderingProgressCoverCreator;
public Builder(Context ctx) {
this.context = ctx;
renderMode = FlutterView.RenderMode.surface;
transparencyMode = FlutterView.TransparencyMode.transparent;
}
public Builder flutterEngine(BoostFlutterEngine engine) {
this.engine = engine;
return this;
}
public Builder renderMode(FlutterView.RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
public Builder renderingProgressCoverCreator(RenderingProgressCoverCreator creator) {
this.renderingProgressCoverCreator = creator;
return this;
}
public Builder transparencyMode(FlutterView.TransparencyMode transparencyMode) {
this.transparencyMode = transparencyMode;
return this;
}
public BoostFlutterView build() {
Bundle args = new Bundle();
args.putString("flutterview_render_mode", renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
args.putString("flutterview_transparency_mode", transparencyMode != null ? transparencyMode.name() : FlutterView.TransparencyMode.transparent.name());
return new BoostFlutterView(context, engine, args,renderingProgressCoverCreator);
}
}
public interface OnFirstFrameRenderedListener {
void onFirstFrameRendered(BoostFlutterView view);
}
public interface RenderingProgressCoverCreator {
View createRenderingProgressCover(Context context);
}
}
...@@ -46,13 +46,13 @@ public class BoostPluginRegistry extends FlutterPluginRegistry { ...@@ -46,13 +46,13 @@ public class BoostPluginRegistry extends FlutterPluginRegistry {
Activity activity; Activity activity;
IContainerRecord record; IContainerRecord record;
record = FlutterBoost.singleton().containerManager().getCurrentTopRecord(); record = NewFlutterBoost.instance().containerManager().getCurrentTopRecord();
if (record == null) { if (record == null) {
record = FlutterBoost.singleton().containerManager().getLastGenerateRecord(); record = NewFlutterBoost.instance().containerManager().getLastGenerateRecord();
} }
if (record == null) { if (record == null) {
activity = FlutterBoost.singleton().currentActivity(); activity = NewFlutterBoost.instance().currentActivity();
} else { } else {
activity = record.getContainer().getContextActivity(); activity = record.getContainer().getContextActivity();
} }
......
...@@ -69,7 +69,6 @@ public class ContainerRecord implements IContainerRecord { ...@@ -69,7 +69,6 @@ public class ContainerRecord implements IContainerRecord {
@Override @Override
public void onCreate() { public void onCreate() {
Utils.assertCallOnMainThread(); Utils.assertCallOnMainThread();
BoostEngineProvider.assertEngineRunning();
if (mState != STATE_UNKNOW) { if (mState != STATE_UNKNOW) {
Debuger.exception("state error"); Debuger.exception("state error");
......
...@@ -60,7 +60,7 @@ public class Debuger { ...@@ -60,7 +60,7 @@ public class Debuger {
public static boolean isDebug(){ public static boolean isDebug(){
try { try {
return FlutterBoost.singleton().platform().isDebug(); return NewFlutterBoost.instance().platform().isDebug();
}catch (Throwable t){ }catch (Throwable t){
return false; return false;
} }
......
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost;
import android.app.Activity;
import android.app.Application;
import android.content.Intent;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.idlefish.flutterboost.interfaces.IContainerManager;
import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IFlutterEngineProvider;
import com.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import com.idlefish.flutterboost.interfaces.IPlatform;
import com.idlefish.flutterboost.interfaces.IStateListener;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class FlutterBoost {
static FlutterBoost sInstance = null;
public static synchronized void init(IPlatform platform) {
if (sInstance == null) {
sInstance = new FlutterBoost(platform);
}
// if (platform.whenEngineStart() == IPlatform.IMMEDIATELY) {
// sInstance.mEngineProvider
// .provideEngine(platform.getApplication())
// .startRun(null);
// }
}
public static FlutterBoost singleton() {
if (sInstance == null) {
throw new RuntimeException("FlutterBoost not init yet");
}
return sInstance;
}
private final IPlatform mPlatform;
private final FlutterViewContainerManager mManager;
private final IFlutterEngineProvider mEngineProvider;
IStateListener mStateListener;
Activity mCurrentActiveActivity;
private FlutterBoost(IPlatform platform) {
mPlatform = platform;
mManager = new FlutterViewContainerManager();
IFlutterEngineProvider provider = platform.engineProvider();
if(provider == null) {
provider = new BoostEngineProvider();
}
mEngineProvider = provider;
platform.getApplication().registerActivityLifecycleCallbacks(new ActivityLifecycleCallbacks());
FlutterBoostPlugin.addActionAfterRegistered(new FlutterBoostPlugin.ActionAfterRegistered() {
@Override
public void onChannelRegistered(FlutterBoostPlugin channel) {
channel.addMethodCallHandler(new BoostMethodHandler());
}
});
}
public IFlutterEngineProvider engineProvider() {
return sInstance.mEngineProvider;
}
public IContainerManager containerManager() {
return sInstance.mManager;
}
public IPlatform 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);
}
public void setStateListener(@Nullable IStateListener listener){
mStateListener = listener;
}
class ActivityLifecycleCallbacks implements Application.ActivityLifecycleCallbacks {
@Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (platform().whenEngineStart() == IPlatform.ANY_ACTIVITY_CREATED) {
// sInstance.mEngineProvider
// .provideEngine(activity)
// .startRun(activity);
}
}
@Override
public void onActivityStarted(Activity activity) {
if (mCurrentActiveActivity == null) {
Debuger.log("Application entry foreground");
if (mEngineProvider.tryGetEngine() != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "foreground");
channel().sendEvent("lifecycle",map);
}
}
mCurrentActiveActivity = activity;
}
@Override
public void onActivityResumed(Activity activity) {
mCurrentActiveActivity = activity;
}
@Override
public void onActivityPaused(Activity activity) {
}
@Override
public void onActivityStopped(Activity activity) {
if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background");
if (mEngineProvider.tryGetEngine() != 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) {
}
@Override
public void onActivityDestroyed(Activity activity) {
if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background");
if (mEngineProvider.tryGetEngine() != null) {
HashMap<String, String> map = new HashMap<>();
map.put("type", "background");
channel().sendEvent("lifecycle",map);
}
mCurrentActiveActivity = null;
}
}
}
class BoostMethodHandler implements MethodChannel.MethodCallHandler {
@Override
public void onMethodCall(MethodCall methodCall, final MethodChannel.Result result) {
switch (methodCall.method) {
case "pageOnStart":
{
Map<String, Object> pageInfo = new HashMap<>();
try {
IContainerRecord record = mManager.getCurrentTopRecord();
if (record == null) {
record = mManager.getLastGenerateRecord();
}
if(record != null) {
pageInfo.put("name", record.getContainer().getContainerUrl());
pageInfo.put("params", record.getContainer().getContainerUrlParams());
pageInfo.put("uniqueId", record.uniqueId());
}
result.success(pageInfo);
} catch (Throwable t) {
result.error("no flutter page found!",t.getMessage(),t);
}
}
break;
case "openPage":
{
try {
Map<String,Object> params = methodCall.argument("urlParams");
Map<String,Object> exts = methodCall.argument("exts");
String url = methodCall.argument("url");
mManager.openContainer(url, params, exts, new FlutterViewContainerManager.OnResult() {
@Override
public void onResult(Map<String, Object> rlt) {
if (result != null) {
result.success(rlt);
}
}
});
}catch (Throwable t){
result.error("open page error",t.getMessage(),t);
}
}
break;
case "closePage":
{
try {
String uniqueId = methodCall.argument("uniqueId");
Map<String,Object> resultData = methodCall.argument("result");
Map<String,Object> exts = methodCall.argument("exts");
mManager.closeContainer(uniqueId, resultData,exts);
result.success(true);
}catch (Throwable t){
result.error("close page error",t.getMessage(),t);
}
}
break;
case "onShownContainerChanged":
{
try {
String newId = methodCall.argument("newName");
String oldId = methodCall.argument("oldName");
mManager.onShownContainerChanged(newId,oldId);
result.success(true);
}catch (Throwable t){
result.error("onShownContainerChanged",t.getMessage(),t);
}
}
break;
default:
{
result.notImplemented();
}
}
}
}
public static void setBoostResult(Activity activity, HashMap result) {
Intent intent = new Intent();
if (result != null) {
intent.putExtra(IFlutterViewContainer.RESULT_KEY, result);
}
activity.setResult(Activity.RESULT_OK, intent);
}
}
...@@ -3,7 +3,6 @@ package com.idlefish.flutterboost; ...@@ -3,7 +3,6 @@ package com.idlefish.flutterboost;
import android.support.annotation.Nullable; import android.support.annotation.Nullable;
import com.idlefish.flutterboost.interfaces.IContainerRecord; import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IStateListener;
import java.io.Serializable; import java.io.Serializable;
import java.util.HashMap; import java.util.HashMap;
...@@ -50,12 +49,12 @@ public class FlutterBoostPlugin { ...@@ -50,12 +49,12 @@ public class FlutterBoostPlugin {
a.onChannelRegistered(sInstance); a.onChannelRegistered(sInstance);
} }
if (FlutterBoost.sInstance != null) { // if (NewFlutterBoost.instance() != null) {
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener; // final IStateListener stateListener = NewFlutterBoost.instance().mStateListener;
if (stateListener != null) { // if (stateListener != null) {
stateListener.onChannelRegistered(registrar, sInstance); // stateListener.onChannelRegistered(registrar, sInstance);
} // }
} // }
sActions.clear(); sActions.clear();
} }
......
...@@ -7,8 +7,11 @@ import android.content.Context; ...@@ -7,8 +7,11 @@ import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import android.support.annotation.NonNull;
import com.idlefish.flutterboost.interfaces.*; import com.idlefish.flutterboost.interfaces.*;
import io.flutter.app.FlutterPluginRegistry; import io.flutter.Log;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.dart.DartExecutor;
import io.flutter.view.FlutterMain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -16,8 +19,9 @@ import java.util.Map; ...@@ -16,8 +19,9 @@ import java.util.Map;
public class NewFlutterBoost { public class NewFlutterBoost {
private Platform mPlatform; private Platform mPlatform;
private FlutterViewContainerManager mManager; private FlutterViewContainerManager mManager;
private IFlutterEngineProvider mEngineProvider;
private Activity mCurrentActiveActivity; private Activity mCurrentActiveActivity;
static NewFlutterBoost sInstance = null; static NewFlutterBoost sInstance = null;
...@@ -35,15 +39,22 @@ public class NewFlutterBoost { ...@@ -35,15 +39,22 @@ public class NewFlutterBoost {
mPlatform = platform; mPlatform = platform;
mManager = new FlutterViewContainerManager(); mManager = new FlutterViewContainerManager();
mEngineProvider = platform.engineProvider();
if (mPlatform.whenEngineStart() == ConfigBuilder.IMMEDIATELY) {
doInitialFlutterViewRun(mPlatform);
}
platform.getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { platform.getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() {
@Override @Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
if (mPlatform.whenEngineStart() == IPlatform.ANY_ACTIVITY_CREATED) { Log.e("bbbb1", "xxxxx");
if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) {
Log.e("bbbb2", "xxxxx");
doInitialFlutterViewRun(mPlatform);
} }
} }
...@@ -52,7 +63,7 @@ public class NewFlutterBoost { ...@@ -52,7 +63,7 @@ public class NewFlutterBoost {
if (mCurrentActiveActivity == null) { if (mCurrentActiveActivity == null) {
Debuger.log("Application entry foreground"); Debuger.log("Application entry foreground");
if (NewFlutterBoost.instance().engineProvider().tryGetEngine() != null) { if (NewFlutterBoost.instance().engineProvider() != null) {
HashMap<String, String> map = new HashMap<>(); HashMap<String, String> map = new HashMap<>();
map.put("type", "foreground"); map.put("type", "foreground");
channel().sendEvent("lifecycle", map); channel().sendEvent("lifecycle", map);
...@@ -76,7 +87,7 @@ public class NewFlutterBoost { ...@@ -76,7 +87,7 @@ public class NewFlutterBoost {
if (mCurrentActiveActivity == activity) { if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background"); Debuger.log("Application entry background");
if (mEngineProvider.tryGetEngine() != null) { if (mPlatform.engineProvider() != null) {
HashMap<String, String> map = new HashMap<>(); HashMap<String, String> map = new HashMap<>();
map.put("type", "background"); map.put("type", "background");
channel().sendEvent("lifecycle", map); channel().sendEvent("lifecycle", map);
...@@ -95,7 +106,7 @@ public class NewFlutterBoost { ...@@ -95,7 +106,7 @@ public class NewFlutterBoost {
if (mCurrentActiveActivity == activity) { if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background"); Debuger.log("Application entry background");
if (mEngineProvider.tryGetEngine() != null) { if (mPlatform.engineProvider() != null) {
HashMap<String, String> map = new HashMap<>(); HashMap<String, String> map = new HashMap<>();
map.put("type", "background"); map.put("type", "background");
channel().sendEvent("lifecycle", map); channel().sendEvent("lifecycle", map);
...@@ -106,21 +117,60 @@ public class NewFlutterBoost { ...@@ -106,21 +117,60 @@ public class NewFlutterBoost {
}); });
BoostPluginRegistry registry=new BoostPluginRegistry(this.engineProvider().provideEngine(mPlatform.getApplication()), BoostPluginRegistry registry = new BoostPluginRegistry(this.engineProvider(),
mPlatform.getApplication()); mPlatform.getApplication());
mPlatform.registerPlugins(registry); mPlatform.registerPlugins(registry);
}
private void doInitialFlutterViewRun(Platform platform) {
// Don't attempt to start a FlutterEngine if we're using a cached FlutterEngine.
// if (host.getCachedEngineId() != null) {
// return;
// }
FlutterEngine flutterEngine = platform.engineProvider();
if (flutterEngine.getDartExecutor().isExecutingDart()) {
// No warning is logged because this situation will happen on every config
// change if the developer does not choose to retain the Fragment instance.
// So this is expected behavior in many cases.
return;
}
Log.e("bbbb3", "xxxxx");
// The engine needs to receive the Flutter app's initial route before executing any
// Dart code to ensure that the initial route arrives in time to be applied.
if (platform.initialRoute() != null) {
flutterEngine.getNavigationChannel().setInitialRoute(platform.initialRoute());
}
// Configure the Dart entrypoint and execute it.
DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint(
FlutterMain.findAppBundlePath(),
"main"
);
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
} }
public static class ConfigBuilder { public static class ConfigBuilder {
protected static final String DEFAULT_DART_ENTRYPOINT = "main"; public static final String DEFAULT_DART_ENTRYPOINT = "main";
protected static final String DEFAULT_INITIAL_ROUTE = "/"; public static final String DEFAULT_INITIAL_ROUTE = "/";
public static int IMMEDIATELY = 0; //立即启动引擎
public static int ANY_ACTIVITY_CREATED = 1; //当有任何Activity创建时,启动引擎
private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT; private String dartEntrypoint = DEFAULT_DART_ENTRYPOINT;
private String initialRoute = DEFAULT_INITIAL_ROUTE; private String initialRoute = DEFAULT_INITIAL_ROUTE;
private int whenEngineStart = ANY_ACTIVITY_CREATED;
private boolean isDebug = false; private boolean isDebug = false;
private int whenEngineStart = 1;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface;
private Application mApp; private Application mApp;
private INativeRouter router = null; private INativeRouter router = null;
...@@ -130,11 +180,21 @@ public class NewFlutterBoost { ...@@ -130,11 +180,21 @@ public class NewFlutterBoost {
this.mApp = app; this.mApp = app;
} }
public ConfigBuilder renderMode(FlutterView.RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
public ConfigBuilder dartEntrypoint(@NonNull String dartEntrypoint) { public ConfigBuilder dartEntrypoint(@NonNull String dartEntrypoint) {
this.dartEntrypoint = dartEntrypoint; this.dartEntrypoint = dartEntrypoint;
return this; return this;
} }
public ConfigBuilder initialRoute(@NonNull String initialRoute) {
this.initialRoute = initialRoute;
return this;
}
public ConfigBuilder isDebug(boolean isDebug) { public ConfigBuilder isDebug(boolean isDebug) {
this.isDebug = isDebug; this.isDebug = isDebug;
return this; return this;
...@@ -148,7 +208,7 @@ public class NewFlutterBoost { ...@@ -148,7 +208,7 @@ public class NewFlutterBoost {
public Platform build() { public Platform build() {
Platform platform = new Platform() { Platform platform = new Platform() {
@Override
public Application getApplication() { public Application getApplication() {
return ConfigBuilder.this.mApp; return ConfigBuilder.this.mApp;
} }
...@@ -159,19 +219,22 @@ public class NewFlutterBoost { ...@@ -159,19 +219,22 @@ public class NewFlutterBoost {
} }
@Override @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) { public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
router.openContainer(context, url, urlParams, requestCode, exts); router.openContainer(context, url, urlParams, requestCode, exts);
} }
@Override
public IFlutterEngineProvider engineProvider() {
return new BoostEngineProvider();
}
public int whenEngineStart() { public int whenEngineStart() {
return ConfigBuilder.this.whenEngineStart; return ConfigBuilder.this.whenEngineStart;
} }
public FlutterView.RenderMode renderMode() {
return ConfigBuilder.this.renderMode;
}
}; };
return platform; return platform;
...@@ -181,15 +244,15 @@ public class NewFlutterBoost { ...@@ -181,15 +244,15 @@ public class NewFlutterBoost {
} }
public IFlutterEngineProvider engineProvider() { public FlutterEngine engineProvider() {
return sInstance.mEngineProvider; return sInstance.mPlatform.engineProvider();
} }
public IContainerManager containerManager() { public IContainerManager containerManager() {
return sInstance.mManager; return sInstance.mManager;
} }
public IPlatform platform() { public Platform platform() {
return sInstance.mPlatform; return sInstance.mPlatform;
} }
......
package com.idlefish.flutterboost; package com.idlefish.flutterboost;
import android.app.Application;
import android.content.Context;
import com.idlefish.flutterboost.interfaces.IContainerRecord; import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IFlutterEngineProvider;
import com.idlefish.flutterboost.interfaces.IPlatform;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.util.Map; import java.util.Map;
import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.plugin.common.PluginRegistry; import io.flutter.plugin.common.PluginRegistry;
import io.flutter.view.FlutterMain;
public abstract class Platform implements IPlatform { public abstract class Platform {
public FlutterEngine mEngine ;
public abstract Application getApplication();
public abstract void openContainer(Context context, String url, Map<String,Object> urlParams, int requestCode, Map<String,Object> exts);
public abstract int whenEngineStart() ;
public abstract FlutterView.RenderMode renderMode();
public abstract boolean isDebug() ;
public abstract String initialRoute();
@Override
public boolean isDebug() {
return false;
}
@Override
public void closeContainer(IContainerRecord record, Map<String, Object> result, Map<String, Object> exts) { public void closeContainer(IContainerRecord record, Map<String, Object> result, Map<String, Object> exts) {
if(record == null) return; if(record == null) return;
record.getContainer().finishContainer(result); record.getContainer().finishContainer(result);
} }
@Override public FlutterEngine engineProvider() {
public IFlutterEngineProvider engineProvider() { if (mEngine == null) {
return new BoostEngineProvider(); FlutterShellArgs flutterShellArgs = new FlutterShellArgs(new String[0]);
FlutterMain.ensureInitializationComplete(
getApplication().getApplicationContext(), flutterShellArgs.toArray());
mEngine = new FlutterEngine( getApplication().getApplicationContext());
}
return mEngine;
} }
@Override
public void registerPlugins(PluginRegistry registry) { public void registerPlugins(PluginRegistry registry) {
try { try {
Class clz = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant"); Class clz = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
...@@ -39,8 +60,5 @@ public abstract class Platform implements IPlatform { ...@@ -39,8 +60,5 @@ public abstract class Platform implements IPlatform {
} }
} }
@Override
public int whenEngineStart() {
return ANY_ACTIVITY_CREATED;
}
} }
package com.idlefish.flutterboost;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Color;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.Gravity;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import java.util.LinkedList;
import java.util.List;
public class SnapshotView extends FrameLayout {
private ImageView mImg;
public SnapshotView(@NonNull Context context) {
super(context);
init();
}
public SnapshotView(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public SnapshotView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init(){
setBackgroundColor(Color.RED);
mImg = new ImageView(getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
mImg.setScaleType(ImageView.ScaleType.FIT_XY);
mImg.setLayoutParams(params);
addView(mImg);
}
public void toggleSnapshot(BoostFlutterView flutterView){
if (!dismissSnapshot(flutterView)) {
showSnapshot(flutterView);
}
}
public boolean showSnapshot(BoostFlutterView flutterView){
if(flutterView == null) return false;
dismissSnapshot(flutterView);
final Bitmap bitmap = flutterView.getEngine().getRenderer().getBitmap();
if(bitmap == null || bitmap.isRecycled()) {
return false;
}
mImg.setImageBitmap(bitmap);
flutterView.addView(this,new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
Debuger.log("showSnapshot");
return true;
}
public boolean dismissSnapshot(BoostFlutterView flutterView){
List<View> snapshots = new LinkedList<>();
for(int index = 0;index < flutterView.getChildCount();index++){
View view = flutterView.getChildAt(index);
if(view instanceof SnapshotView) {
snapshots.add(view);
}
}
if(snapshots.isEmpty()) {
return false;
}else{
for(View v:snapshots) {
flutterView.removeView(v);
}
Debuger.log("dismissSnapshot");
return true;
}
}
}
package com.idlefish.flutterboost;
import com.idlefish.flutterboost.interfaces.IStateListener;
import io.flutter.plugin.common.PluginRegistry;
public class StateListener implements IStateListener {
@Override
public void onEngineCreated(BoostFlutterEngine engine) {
Debuger.log(">>onEngineCreated");
}
@Override
public void onEngineStarted(BoostFlutterEngine engine) {
Debuger.log(">>onEngineStarted");
}
@Override
public void onChannelRegistered(PluginRegistry.Registrar registrar, FlutterBoostPlugin channel) {
Debuger.log(">>onFlutterViewInited");
}
@Override
public void onFlutterViewInited(BoostFlutterEngine engine, BoostFlutterView flutterView) {
Debuger.log(">>onFlutterViewInited");
}
@Override
public void beforeEngineAttach(BoostFlutterEngine engine, BoostFlutterView flutterView) {
Debuger.log(">>beforeEngineAttach");
}
@Override
public void afterEngineAttached(BoostFlutterEngine engine, BoostFlutterView flutterView) {
Debuger.log(">>afterEngineAttached");
}
@Override
public void beforeEngineDetach(BoostFlutterEngine engine, BoostFlutterView flutterView) {
Debuger.log(">>beforeEngineDetach");
}
@Override
public void afterEngineDetached(BoostFlutterEngine engine, BoostFlutterView flutterView) {
Debuger.log(">>afterEngineDetached");
}
}
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost.containers;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.drawable.ColorDrawable;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.view.Gravity;
import android.view.KeyEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import android.widget.TextView;
import com.idlefish.flutterboost.BoostFlutterEngine;
import com.idlefish.flutterboost.BoostFlutterView;
import com.idlefish.flutterboost.FlutterBoost;
import com.idlefish.flutterboost.Utils;
import com.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import com.idlefish.flutterboost.interfaces.IOperateSyncer;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.platform.PlatformPlugin;
public abstract class BoostFlutterActivity extends Activity implements IFlutterViewContainer {
protected BoostFlutterEngine mFlutterEngine;
protected BoostFlutterView mFlutterView;
protected IOperateSyncer mSyncer;
private Handler mHandler = new Handler(Looper.getMainLooper());
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
configureWindowForTransparency();
mSyncer = FlutterBoost.singleton().containerManager().generateSyncer(this);
mFlutterEngine = createFlutterEngine();
mFlutterView = createFlutterView(mFlutterEngine);
setContentView(mFlutterView);
mSyncer.onCreate();
configureStatusBarForFullscreenFlutterExperience();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
mHandler.post(new Runnable() {
@Override
public void run() {
configureStatusBarForFullscreenFlutterExperience();
}
});
}
protected void configureWindowForTransparency() {
if (isBackgroundTransparent()) {
getWindow().setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT));
getWindow().setFlags(
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS,
WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
);
}
}
protected void configureStatusBarForFullscreenFlutterExperience() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
Window window = getWindow();
window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.setStatusBarColor(Color.TRANSPARENT);
window.getDecorView().setSystemUiVisibility(PlatformPlugin.DEFAULT_SYSTEM_UI);
}
Utils.setStatusBarLightMode(this,true);
}
protected BoostFlutterEngine createFlutterEngine(){
// return FlutterBoost.singleton().engineProvider().provideEngine(this);
return null;
}
protected BoostFlutterView createFlutterView(BoostFlutterEngine engine){
BoostFlutterView.Builder builder = new BoostFlutterView.Builder(this);
return builder.flutterEngine(engine)
.renderMode(FlutterView.RenderMode.texture)
.transparencyMode(isBackgroundTransparent() ?
FlutterView.TransparencyMode.transparent :
FlutterView.TransparencyMode.opaque)
.renderingProgressCoverCreator(new BoostFlutterView.RenderingProgressCoverCreator() {
@Override
public View createRenderingProgressCover(Context context) {
return BoostFlutterActivity.this.createRenderingProgressCover();
}
})
.build();
}
protected boolean isBackgroundTransparent(){
return false;
}
protected View createRenderingProgressCover(){
FrameLayout frameLayout = new FrameLayout(this);
LinearLayout linearLayout = new LinearLayout(this);
linearLayout.setOrientation(LinearLayout.VERTICAL);
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.gravity = Gravity.CENTER;
frameLayout.addView(linearLayout,layoutParams);
ProgressBar progressBar = new ProgressBar(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
linearLayout.addView(progressBar,params);
TextView textView = new TextView(this);
params = new LinearLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER_HORIZONTAL;
textView.setText("Frame Rendering...");
linearLayout.addView(textView,params);
return frameLayout;
}
@Override
protected void onResume() {
super.onResume();
mSyncer.onAppear();
mFlutterEngine.getLifecycleChannel().appIsResumed();
}
@Override
protected void onPause() {
mSyncer.onDisappear();
super.onPause();
mFlutterEngine.getLifecycleChannel().appIsInactive();
}
@Override
protected void onDestroy() {
Utils.fixInputMethodManagerLeak(this);
mSyncer.onDestroy();
super.onDestroy();
}
@Override
public void onBackPressed() {
mSyncer.onBackPressed();
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
mSyncer.onNewIntent(intent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mSyncer.onActivityResult(requestCode,resultCode,data);
Map<String,Object> result = null;
if(data != null) {
Serializable rlt = data.getSerializableExtra(RESULT_KEY);
if(rlt instanceof Map) {
result = (Map<String,Object>)rlt;
}
}
mSyncer.onContainerResult(requestCode,resultCode,result);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mSyncer.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onTrimMemory(int level) {
super.onTrimMemory(level);
mSyncer.onTrimMemory(level);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mSyncer.onLowMemory();
}
@Override
protected void onUserLeaveHint() {
super.onUserLeaveHint();
mSyncer.onUserLeaveHint();
}
@Override
public Activity getContextActivity() {
return this;
}
// @Override
// public BoostFlutterView getBoostFlutterView() {
// return mFlutterView;
// }
@Override
public void finishContainer(Map<String,Object> result) {
if(result != null) {
FlutterBoost.setBoostResult(this,new HashMap<>(result));
finish();
}else{
finish();
}
}
@Override
public void onContainerShown() {}
@Override
public void onContainerHidden() {}
}
package com.idlefish.flutterboost.containers;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import java.util.HashMap;
import java.util.Map;
public class BoostFlutterDefaultActivity extends BoostFlutterActivity {
@Override
public FlutterSplashView getBoostFlutterView() {
return null;
}
@Override
public String getContainerUrl() {
return getIntent().getStringExtra("url");
}
@Override
public Map getContainerUrlParams() {
return (Map)(getIntent().getSerializableExtra("params"));
}
private static Intent intent(Context context, String url, HashMap<String, Object> params) {
final Intent intent = new Intent(context, BoostFlutterDefaultActivity.class);
intent.putExtra("url", url);
intent.putExtra("params", params);
return intent;
}
public static void open(Context context, String url, HashMap<String, Object> params) {
context.startActivity(intent(context, url, params));
}
public static void open(Activity activity, String url, HashMap<String, Object> params, int requestCode) {
activity.startActivityForResult(intent(activity, url, params), requestCode);
}
}
\ No newline at end of file
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost.containers;
import android.app.Activity;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.Window;
import android.view.WindowManager;
import com.idlefish.flutterboost.BoostFlutterEngine;
import com.idlefish.flutterboost.BoostFlutterView;
import com.idlefish.flutterboost.FlutterBoost;
import com.idlefish.flutterboost.Utils;
import com.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import com.idlefish.flutterboost.interfaces.IOperateSyncer;
import java.util.Map;
import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.platform.PlatformPlugin;
abstract public class BoostFlutterFragment extends Fragment implements IFlutterViewContainer {
protected BoostFlutterEngine mFlutterEngine;
protected BoostFlutterView mFlutterView;
protected IOperateSyncer mSyncer;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mSyncer = FlutterBoost.singleton().containerManager().generateSyncer(this);
mFlutterEngine = createFlutterEngine();
mFlutterView = createFlutterView(mFlutterEngine);
mSyncer.onCreate();
return mFlutterView;
}
protected BoostFlutterEngine createFlutterEngine(){
// return FlutterBoost.singleton().engineProvider().provideEngine(getContext());
return null;
}
protected BoostFlutterView createFlutterView(BoostFlutterEngine engine){
BoostFlutterView.Builder builder = new BoostFlutterView.Builder(getContextActivity());
return builder.flutterEngine(engine)
.renderMode(FlutterView.RenderMode.texture)
.transparencyMode(FlutterView.TransparencyMode.opaque)
.build();
}
@Override
public void onResume() {
super.onResume();
mSyncer.onAppear();
mFlutterEngine.getLifecycleChannel().appIsResumed();
}
@Override
public void onPause() {
mSyncer.onDisappear();
super.onPause();
mFlutterEngine.getLifecycleChannel().appIsInactive();
}
@Override
public void onDestroy() {
mSyncer.onDestroy();
super.onDestroy();
}
public void onBackPressed() {
mSyncer.onBackPressed();
}
public void onNewIntent(Intent intent) {
mSyncer.onNewIntent(intent);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mSyncer.onActivityResult(requestCode,resultCode,data);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mSyncer.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
public void onTrimMemory(int level) {
mSyncer.onTrimMemory(level);
}
@Override
public void onLowMemory() {
super.onLowMemory();
mSyncer.onLowMemory();
}
public void onUserLeaveHint() {
mSyncer.onUserLeaveHint();
}
@Override
public Activity getContextActivity() {
return getActivity();
}
// @Override
// public BoostFlutterView getBoostFlutterView() {
// return mFlutterView;
// }
@Override
public void finishContainer(Map<String,Object> result) {
getFragmentManager().popBackStack();
}
@Override
public void onContainerShown() {}
@Override
public void onContainerHidden() {}
}
...@@ -19,8 +19,7 @@ import java.util.Arrays; ...@@ -19,8 +19,7 @@ import java.util.Arrays;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
import com.idlefish.flutterboost.BoostFlutterView;
import com.idlefish.flutterboost.FlutterBoost;
import com.idlefish.flutterboost.NewFlutterBoost; import com.idlefish.flutterboost.NewFlutterBoost;
import com.idlefish.flutterboost.interfaces.IFlutterViewContainer; import com.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import com.idlefish.flutterboost.interfaces.IOperateSyncer; import com.idlefish.flutterboost.interfaces.IOperateSyncer;
...@@ -63,7 +62,9 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -63,7 +62,9 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() { private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
@Override @Override
public void onFirstFrameRendered() { public void onFirstFrameRendered() {
host.onFirstFrameRendered(); if(host!=null){
host.onFirstFrameRendered();
}
} }
}; };
...@@ -136,15 +137,15 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -136,15 +137,15 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
Log.d(TAG, "Setting up FlutterEngine."); Log.d(TAG, "Setting up FlutterEngine.");
// First, check if the host wants to use a cached FlutterEngine. // First, check if the host wants to use a cached FlutterEngine.
String cachedEngineId = host.getCachedEngineId(); // String cachedEngineId = host.getCachedEngineId();
if (cachedEngineId != null) { // if (cachedEngineId != null) {
flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId); // flutterEngine = FlutterEngineCache.getInstance().get(cachedEngineId);
isFlutterEngineFromHost = true; // isFlutterEngineFromHost = true;
if (flutterEngine == null) { // if (flutterEngine == null) {
throw new IllegalStateException("The requested cached FlutterEngine did not exist in the FlutterEngineCache: '" + cachedEngineId + "'"); // throw new IllegalStateException("The requested cached FlutterEngine did not exist in the FlutterEngineCache: '" + cachedEngineId + "'");
} // }
return; // return;
} // }
// Second, defer to subclasses for a custom FlutterEngine. // Second, defer to subclasses for a custom FlutterEngine.
flutterEngine = host.provideFlutterEngine(host.getContext()); flutterEngine = host.provideFlutterEngine(host.getContext());
...@@ -170,7 +171,8 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -170,7 +171,8 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
mSyncer = NewFlutterBoost.instance().containerManager().generateSyncer(this); mSyncer = NewFlutterBoost.instance().containerManager().generateSyncer(this);
ensureAlive(); ensureAlive();
flutterView = new FlutterView(host.getActivity(), host.getRenderMode(), host.getTransparencyMode()); flutterView = new FlutterView(host.getActivity(), NewFlutterBoost.instance().platform().renderMode(), host.getTransparencyMode());
flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener); flutterView.addOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
flutterSplashView = new FlutterSplashView(host.getContext()); flutterSplashView = new FlutterSplashView(host.getContext());
...@@ -197,48 +199,10 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -197,48 +199,10 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
// causes launching Activitys to wait a second or two before launching. By post()'ing this // causes launching Activitys to wait a second or two before launching. By post()'ing this
// behavior we are able to move this blocking logic to after the Activity's launch. // behavior we are able to move this blocking logic to after the Activity's launch.
// TODO(mattcarroll): figure out how to avoid blocking the MAIN thread when connecting a surface // TODO(mattcarroll): figure out how to avoid blocking the MAIN thread when connecting a surface
new Handler().post(new Runnable() {
@Override
public void run() {
Log.v(TAG, "Attaching FlutterEngine to FlutterView.");
flutterView.attachToFlutterEngine(flutterEngine);
doInitialFlutterViewRun();
}
});
} }
private void doInitialFlutterViewRun() {
// Don't attempt to start a FlutterEngine if we're using a cached FlutterEngine.
if (host.getCachedEngineId() != null) {
return;
}
if (flutterEngine.getDartExecutor().isExecutingDart()) {
// No warning is logged because this situation will happen on every config
// change if the developer does not choose to retain the Fragment instance.
// So this is expected behavior in many cases.
return;
}
Log.d(TAG, "Executing Dart entrypoint: " + host.getDartEntrypointFunctionName()
+ ", and sending initial route: " + host.getInitialRoute());
// The engine needs to receive the Flutter app's initial route before executing any
// Dart code to ensure that the initial route arrives in time to be applied.
if (host.getInitialRoute() != null) {
flutterEngine.getNavigationChannel().setInitialRoute(host.getInitialRoute());
}
// Configure the Dart entrypoint and execute it.
DartExecutor.DartEntrypoint entrypoint = new DartExecutor.DartEntrypoint(
host.getAppBundlePath(),
host.getDartEntrypointFunctionName()
);
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
}
void onResume() { void onResume() {
mSyncer.onAppear(); mSyncer.onAppear();
...@@ -267,7 +231,6 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -267,7 +231,6 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
void onPause() { void onPause() {
Log.v(TAG, "onPause()"); Log.v(TAG, "onPause()");
mSyncer.onDisappear();
ensureAlive(); ensureAlive();
flutterEngine.getLifecycleChannel().appIsInactive(); flutterEngine.getLifecycleChannel().appIsInactive();
...@@ -277,8 +240,9 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -277,8 +240,9 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
void onStop() { void onStop() {
Log.v(TAG, "onStop()"); Log.v(TAG, "onStop()");
ensureAlive(); ensureAlive();
mSyncer.onDisappear();
flutterEngine.getLifecycleChannel().appIsPaused(); flutterEngine.getLifecycleChannel().appIsPaused();
flutterView.detachFromFlutterEngine(); // flutterView.detachFromFlutterEngine();
} }
void onDestroyView() { void onDestroyView() {
...@@ -286,7 +250,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -286,7 +250,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
mSyncer.onDestroy(); mSyncer.onDestroy();
ensureAlive(); ensureAlive();
flutterView.removeOnFirstFrameRenderedListener(onFirstFrameRenderedListener); // flutterView.removeOnFirstFrameRenderedListener(onFirstFrameRenderedListener);
} }
...@@ -312,15 +276,15 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -312,15 +276,15 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
} }
// Destroy our FlutterEngine if we're not set to retain it. // Destroy our FlutterEngine if we're not set to retain it.
if (host.shouldDestroyEngineWithHost()) { // if (host.shouldDestroyEngineWithHost()) {
flutterEngine.destroy(); // flutterEngine.destroy();
//
if (host.getCachedEngineId() != null) { // if (host.getCachedEngineId() != null) {
FlutterEngineCache.getInstance().remove(host.getCachedEngineId()); // FlutterEngineCache.getInstance().remove(host.getCachedEngineId());
} // }
//
flutterEngine = null; // flutterEngine = null;
} // }
} }
...@@ -440,7 +404,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -440,7 +404,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
@Override @Override
public Activity getContextActivity() { public Activity getContextActivity() {
return (Activity)this.host; return (Activity)this.host.getActivity();
} }
@Override @Override
...@@ -450,19 +414,19 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -450,19 +414,19 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
@Override @Override
public void finishContainer(Map<String, Object> result) { public void finishContainer(Map<String, Object> result) {
Activity activity= (Activity)this.host; this.host.finishContainer(result);
activity.finish();
} }
@Override @Override
public String getContainerUrl() { public String getContainerUrl() {
return "flutterPage"; return this.host.getContainerUrl();
} }
@Override @Override
public Map getContainerUrlParams() { public Map getContainerUrlParams() {
return null; return this.host.getContainerUrlParams();
} }
@Override @Override
...@@ -590,6 +554,16 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine ...@@ -590,6 +554,16 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContaine
* frame. * frame.
*/ */
void onFirstFrameRendered(); void onFirstFrameRendered();
void finishContainer(Map<String, Object> result) ;
String getContainerUrl() ;
Map getContainerUrlParams() ;
} }
......
package com.idlefish.flutterboost.containers;
import android.app.Activity;
import android.arch.lifecycle.Lifecycle;
import android.content.Context;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import com.idlefish.flutterboost.NewFlutterBoost;
import io.flutter.embedding.android.*;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.embedding.engine.FlutterShellArgs;
import io.flutter.embedding.engine.renderer.OnFirstFrameRenderedListener;
import io.flutter.plugin.platform.PlatformPlugin;
import io.flutter.view.FlutterMain;
import java.util.HashMap;
import java.util.Map;
public class FlutterFragment extends Fragment implements FlutterActivityAndFragmentDelegate.Host {
private static final String TAG = "FlutterFragment";
/**
* The Dart entrypoint method name that is executed upon initialization.
*/
protected static final String ARG_DART_ENTRYPOINT = "dart_entrypoint";
/**
* Initial Flutter route that is rendered in a Navigator widget.
*/
protected static final String ARG_INITIAL_ROUTE = "initial_route";
/**
* Path to Flutter's Dart code.
*/
protected static final String ARG_APP_BUNDLE_PATH = "app_bundle_path";
/**
* Flutter shell arguments.
*/
protected static final String ARG_FLUTTER_INITIALIZATION_ARGS = "initialization_args";
/**
* {@link FlutterView.RenderMode} to be used for the {@link FlutterView} in this
* {@code FlutterFragment}
*/
protected static final String ARG_FLUTTERVIEW_RENDER_MODE = "flutterview_render_mode";
/**
* {@link FlutterView.TransparencyMode} to be used for the {@link FlutterView} in this
* {@code FlutterFragment}
*/
protected static final String ARG_FLUTTERVIEW_TRANSPARENCY_MODE = "flutterview_transparency_mode";
/**
* See {@link #shouldAttachEngineToActivity()}.
*/
protected static final String ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY = "should_attach_engine_to_activity";
/**
* the created {@code FlutterFragment}.
*/
protected static final String ARG_CACHED_ENGINE_ID = "cached_engine_id";
/**
* True if the {@link FlutterEngine} in the created {@code FlutterFragment} should be destroyed
* when the {@code FlutterFragment} is destroyed, false if the {@link FlutterEngine} should
* outlive the {@code FlutterFragment}.
*/
protected static final String ARG_DESTROY_ENGINE_WITH_FRAGMENT = "destroy_engine_with_fragment";
/**
* Creates a {@code FlutterFragment} with a default configuration.
* <p>
* {@code FlutterFragment}'s default configuration creates a new {@link FlutterEngine} within
* the {@code FlutterFragment} and uses the following settings:
* <ul>
* <li>Dart entrypoint: "main"</li>
* <li>Initial route: "/"</li>
* <li>Render mode: surface</li>
* <li>Transparency mode: transparent</li>
* </ul>
* <p>
* To use a new {@link FlutterEngine} with different settings, use {@link #withNewEngine()}.
* <p>
* To use a cached {@link FlutterEngine} instead of creating a new one, use
*/
@NonNull
public static FlutterFragment createDefault() {
return new NewEngineFragmentBuilder().build();
}
/**
* Returns a {@link NewEngineFragmentBuilder} to create a {@code FlutterFragment} with a new
* {@link FlutterEngine} and a desired engine configuration.
*/
@NonNull
public static NewEngineFragmentBuilder withNewEngine() {
return new NewEngineFragmentBuilder();
}
/**
* Builder that creates a new {@code FlutterFragment} with {@code arguments} that correspond
* to the values set on this {@code NewEngineFragmentBuilder}.
* <p>
* To create a {@code FlutterFragment} with default {@code arguments}, invoke
* {@link #createDefault()}.
* <p>
* Subclasses of {@code FlutterFragment} that do not introduce any new arguments can use this
* {@code NewEngineFragmentBuilder} to construct instances of the subclass without subclassing
* this {@code NewEngineFragmentBuilder}.
* {@code
* MyFlutterFragment f = new FlutterFragment.NewEngineFragmentBuilder(MyFlutterFragment.class)
* .someProperty(...)
* .someOtherProperty(...)
* .build<MyFlutterFragment>();
* }
* <p>
* Subclasses of {@code FlutterFragment} that introduce new arguments should subclass this
* {@code NewEngineFragmentBuilder} to add the new properties:
* <ol>
* <li>Ensure the {@code FlutterFragment} subclass has a no-arg constructor.</li>
* <li>Subclass this {@code NewEngineFragmentBuilder}.</li>
* <li>Override the new {@code NewEngineFragmentBuilder}'s no-arg constructor and invoke the
* super constructor to set the {@code FlutterFragment} subclass: {@code
* public MyBuilder() {
* super(MyFlutterFragment.class);
* }
* }</li>
* <li>Add appropriate property methods for the new properties.</li>
* <li>Override {@link NewEngineFragmentBuilder#createArgs()}, call through to the super method,
* then add the new properties as arguments in the {@link Bundle}.</li>
* </ol>
* Once a {@code NewEngineFragmentBuilder} subclass is defined, the {@code FlutterFragment}
* subclass can be instantiated as follows.
* {@code
* MyFlutterFragment f = new MyBuilder()
* .someExistingProperty(...)
* .someNewProperty(...)
* .build<MyFlutterFragment>();
* }
*/
public static class NewEngineFragmentBuilder {
private final Class<? extends FlutterFragment> fragmentClass;
private String dartEntrypoint = "main";
private String initialRoute = "/";
private String appBundlePath = null;
private FlutterShellArgs shellArgs = null;
private FlutterView.RenderMode renderMode = FlutterView.RenderMode.surface;
private FlutterView.TransparencyMode transparencyMode = FlutterView.TransparencyMode.transparent;
private boolean shouldAttachEngineToActivity = true;
/**
* Constructs a {@code NewEngineFragmentBuilder} that is configured to construct an instance of
* {@code FlutterFragment}.
*/
public NewEngineFragmentBuilder() {
fragmentClass = FlutterFragment.class;
}
/**
* Constructs a {@code NewEngineFragmentBuilder} that is configured to construct an instance of
* {@code subclass}, which extends {@code FlutterFragment}.
*/
public NewEngineFragmentBuilder(@NonNull Class<? extends FlutterFragment> subclass) {
fragmentClass = subclass;
}
/**
* The name of the initial Dart method to invoke, defaults to "main".
*/
@NonNull
public NewEngineFragmentBuilder dartEntrypoint(@NonNull String dartEntrypoint) {
this.dartEntrypoint = dartEntrypoint;
return this;
}
/**
* The initial route that a Flutter app will render in this {@link FlutterFragment},
* defaults to "/".
*/
@NonNull
public NewEngineFragmentBuilder initialRoute(@NonNull String initialRoute) {
this.initialRoute = initialRoute;
return this;
}
/**
* The path to the app bundle which contains the Dart app to execute, defaults
* to {@link FlutterMain#findAppBundlePath()}
*/
@NonNull
public NewEngineFragmentBuilder appBundlePath(@NonNull String appBundlePath) {
this.appBundlePath = appBundlePath;
return this;
}
/**
* Any special configuration arguments for the Flutter engine
*/
@NonNull
public NewEngineFragmentBuilder flutterShellArgs(@NonNull FlutterShellArgs shellArgs) {
this.shellArgs = shellArgs;
return this;
}
/**
* Render Flutter either as a {@link FlutterView.RenderMode#surface} or a
* {@link FlutterView.RenderMode#texture}. You should use {@code surface} unless
* you have a specific reason to use {@code texture}. {@code texture} comes with
* a significant performance impact, but {@code texture} can be displayed
* beneath other Android {@code View}s and animated, whereas {@code surface}
* cannot.
*/
@NonNull
public NewEngineFragmentBuilder renderMode(@NonNull FlutterView.RenderMode renderMode) {
this.renderMode = renderMode;
return this;
}
/**
* Support a {@link FlutterView.TransparencyMode#transparent} background within {@link FlutterView},
* or force an {@link FlutterView.TransparencyMode#opaque} background.
* <p>
* See {@link FlutterView.TransparencyMode} for implications of this selection.
*/
@NonNull
public NewEngineFragmentBuilder transparencyMode(@NonNull FlutterView.TransparencyMode transparencyMode) {
this.transparencyMode = transparencyMode;
return this;
}
@NonNull
public NewEngineFragmentBuilder shouldAttachEngineToActivity(boolean shouldAttachEngineToActivity) {
this.shouldAttachEngineToActivity = shouldAttachEngineToActivity;
return this;
}
@NonNull
protected Bundle createArgs() {
Bundle args = new Bundle();
args.putString(ARG_INITIAL_ROUTE, initialRoute);
args.putString(ARG_APP_BUNDLE_PATH, appBundlePath);
args.putString(ARG_DART_ENTRYPOINT, dartEntrypoint);
// TODO(mattcarroll): determine if we should have an explicit FlutterTestFragment instead of conflating.
if (null != shellArgs) {
args.putStringArray(ARG_FLUTTER_INITIALIZATION_ARGS, shellArgs.toArray());
}
args.putString(ARG_FLUTTERVIEW_RENDER_MODE, renderMode != null ? renderMode.name() : FlutterView.RenderMode.surface.name());
args.putString(ARG_FLUTTERVIEW_TRANSPARENCY_MODE, transparencyMode != null ? transparencyMode.name() : FlutterView.TransparencyMode.transparent.name());
args.putBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY, shouldAttachEngineToActivity);
args.putBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, true);
return args;
}
/**
* Constructs a new {@code FlutterFragment} (or a subclass) that is configured based on
* properties set on this {@code Builder}.
*/
@NonNull
public <T extends FlutterFragment> T build() {
try {
@SuppressWarnings("unchecked")
T frag = (T) fragmentClass.getDeclaredConstructor().newInstance();
if (frag == null) {
throw new RuntimeException("The FlutterFragment subclass sent in the constructor ("
+ fragmentClass.getCanonicalName() + ") does not match the expected return type.");
}
Bundle args = createArgs();
frag.setArguments(args);
return frag;
} catch (Exception e) {
throw new RuntimeException("Could not instantiate FlutterFragment subclass (" + fragmentClass.getName() + ")", e);
}
}
}
// Delegate that runs all lifecycle and OS hook logic that is common between
// FlutterActivity and FlutterFragment. See the FlutterActivityAndFragmentDelegate
// implementation for details about why it exists.
private FlutterActivityAndFragmentDelegate delegate;
private final OnFirstFrameRenderedListener onFirstFrameRenderedListener = new OnFirstFrameRenderedListener() {
@Override
public void onFirstFrameRendered() {
// Notify our subclasses that the first frame has been rendered.
FlutterFragment.this.onFirstFrameRendered();
// Notify our owning Activity that the first frame has been rendered.
FragmentActivity fragmentActivity = getActivity();
if (fragmentActivity instanceof OnFirstFrameRenderedListener) {
OnFirstFrameRenderedListener activityAsListener = (OnFirstFrameRenderedListener) fragmentActivity;
activityAsListener.onFirstFrameRendered();
}
}
};
public FlutterFragment() {
// Ensure that we at least have an empty Bundle of arguments so that we don't
// need to continually check for null arguments before grabbing one.
setArguments(new Bundle());
}
@Override
public void onAttach(@NonNull Context context) {
super.onAttach(context);
delegate = new FlutterActivityAndFragmentDelegate(this);
delegate.onAttach(context);
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
return delegate.onCreateView(inflater, container, savedInstanceState);
}
@Override
public void onStart() {
super.onStart();
delegate.onStart();
}
@Override
public void onResume() {
super.onResume();
delegate.onResume();
}
// TODO(mattcarroll): determine why this can't be in onResume(). Comment reason, or move if possible.
@ActivityCallThrough
public void onPostResume() {
delegate.onPostResume();
}
@Override
public void onPause() {
super.onPause();
delegate.onPause();
}
@Override
public void onStop() {
super.onStop();
delegate.onStop();
}
@Override
public void onDestroyView() {
super.onDestroyView();
delegate.onDestroyView();
}
@Override
public void onDetach() {
super.onDetach();
delegate.onDetach();
delegate.release();
delegate = null;
}
@ActivityCallThrough
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
delegate.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@ActivityCallThrough
public void onNewIntent(@NonNull Intent intent) {
delegate.onNewIntent(intent);
}
@ActivityCallThrough
public void onBackPressed() {
delegate.onBackPressed();
}
/**
* A result has been returned after an invocation of {@link Fragment#startActivityForResult(Intent, int)}.
* <p>
*
* @param requestCode request code sent with {@link Fragment#startActivityForResult(Intent, int)}
* @param resultCode code representing the result of the {@code Activity} that was launched
* @param data any corresponding return data, held within an {@code Intent}
*/
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
delegate.onActivityResult(requestCode, resultCode, data);
}
@ActivityCallThrough
public void onUserLeaveHint() {
delegate.onUserLeaveHint();
}
/**
* Callback invoked when memory is low.
* <p>
* This implementation forwards a memory pressure warning to the running Flutter app.
* <p>
*
* @param level level
*/
@ActivityCallThrough
public void onTrimMemory(int level) {
delegate.onTrimMemory(level);
}
/**
* Callback invoked when memory is low.
* <p>
* This implementation forwards a memory pressure warning to the running Flutter app.
*/
@Override
public void onLowMemory() {
super.onLowMemory();
delegate.onLowMemory();
}
@NonNull
private Context getContextCompat() {
return Build.VERSION.SDK_INT >= 23
? getContext()
: getActivity();
}
/**
* {@link FlutterActivityAndFragmentDelegate.Host} method that is used by
* {@link FlutterActivityAndFragmentDelegate} to obtain Flutter shell arguments when
* initializing Flutter.
*/
@Override
@NonNull
public FlutterShellArgs getFlutterShellArgs() {
String[] flutterShellArgsArray = getArguments().getStringArray(ARG_FLUTTER_INITIALIZATION_ARGS);
return new FlutterShellArgs(
flutterShellArgsArray != null ? flutterShellArgsArray : new String[]{}
);
}
/**
* Returns the ID of a statically cached {@link FlutterEngine} to use within this
* {@code FlutterFragment}, or {@code null} if this {@code FlutterFragment} does not want to
* use a cached {@link FlutterEngine}.
*/
@Nullable
@Override
public String getCachedEngineId() {
return getArguments().getString(ARG_CACHED_ENGINE_ID, null);
}
/**
* Returns false if the {@link FlutterEngine} within this {@code FlutterFragment} should outlive
* the {@code FlutterFragment}, itself.
* <p>
* Defaults to true if no custom {@link FlutterEngine is provided}, false if a custom
* {@link FlutterEngine} is provided.
*/
@Override
public boolean shouldDestroyEngineWithHost() {
return getArguments().getBoolean(ARG_DESTROY_ENGINE_WITH_FRAGMENT, false);
}
/**
* Returns the name of the Dart method that this {@code FlutterFragment} should execute to
* start a Flutter app.
* <p>
* Defaults to "main".
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public String getDartEntrypointFunctionName() {
return getArguments().getString(ARG_DART_ENTRYPOINT, "main");
}
/**
* Returns the file path to the desired Flutter app's bundle of code.
* <p>
* Defaults to {@link FlutterMain#findAppBundlePath()}.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public String getAppBundlePath() {
return getArguments().getString(ARG_APP_BUNDLE_PATH, FlutterMain.findAppBundlePath());
}
/**
* Returns the initial route that should be rendered within Flutter, once the Flutter app starts.
* <p>
* Defaults to {@code null}, which signifies a route of "/" in Flutter.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@Nullable
public String getInitialRoute() {
return getArguments().getString(ARG_INITIAL_ROUTE);
}
/**
* Returns the desired {@link FlutterView.RenderMode} for the {@link FlutterView} displayed in
* this {@code FlutterFragment}.
* <p>
* Defaults to {@link FlutterView.RenderMode#surface}.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public FlutterView.RenderMode getRenderMode() {
String renderModeName = getArguments().getString(
ARG_FLUTTERVIEW_RENDER_MODE,
FlutterView.RenderMode.surface.name()
);
return FlutterView.RenderMode.valueOf(renderModeName);
}
/**
* Returns the desired {@link FlutterView.TransparencyMode} for the {@link FlutterView} displayed in
* this {@code FlutterFragment}.
* <p>
* Defaults to {@link FlutterView.TransparencyMode#transparent}.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
@NonNull
public FlutterView.TransparencyMode getTransparencyMode() {
String transparencyModeName = getArguments().getString(
ARG_FLUTTERVIEW_TRANSPARENCY_MODE,
FlutterView.TransparencyMode.transparent.name()
);
return FlutterView.TransparencyMode.valueOf(transparencyModeName);
}
@Override
@Nullable
public SplashScreen provideSplashScreen() {
FragmentActivity parentActivity = getActivity();
if (parentActivity instanceof SplashScreenProvider) {
SplashScreenProvider splashScreenProvider = (SplashScreenProvider) parentActivity;
return splashScreenProvider.provideSplashScreen();
}
return null;
}
@Override
@Nullable
public FlutterEngine provideFlutterEngine(@NonNull Context context) {
return NewFlutterBoost.instance().engineProvider();
// // Defer to the FragmentActivity that owns us to see if it wants to provide a
// // FlutterEngine.
// FlutterEngine flutterEngine = null;
// FragmentActivity attachedActivity = getActivity();
// if (attachedActivity instanceof FlutterEngineProvider) {
// // Defer to the Activity that owns us to provide a FlutterEngine.
// Log.d(TAG, "Deferring to attached Activity to provide a FlutterEngine.");
// FlutterEngineProvider flutterEngineProvider = (FlutterEngineProvider) attachedActivity;
// flutterEngine = flutterEngineProvider.provideFlutterEngine(getContext());
// }
//
// return flutterEngine;
}
/**
* Hook for subclasses to obtain a reference to the {@link FlutterEngine} that is owned
* by this {@code FlutterActivity}.
*/
@Nullable
public FlutterEngine getFlutterEngine() {
return delegate.getFlutterEngine();
}
@Nullable
@Override
public PlatformPlugin providePlatformPlugin(@Nullable Activity activity, @NonNull FlutterEngine flutterEngine) {
if (activity != null) {
return new PlatformPlugin(getActivity(), flutterEngine.getPlatformChannel());
} else {
return null;
}
}
/**
* Configures a {@link FlutterEngine} after its creation.
* <p>
* This method is called after {@link #provideFlutterEngine(Context)}, and after the given
* {@link FlutterEngine} has been attached to the owning {@code FragmentActivity}. See
* {@link io.flutter.embedding.engine.plugins.activity.ActivityControlSurface#attachToActivity(Activity, Lifecycle)}.
* <p>
* It is possible that the owning {@code FragmentActivity} opted not to connect itself as
* an {@link io.flutter.embedding.engine.plugins.activity.ActivityControlSurface}. In that
* case, any configuration, e.g., plugins, must not expect or depend upon an available
* {@code Activity} at the time that this method is invoked.
* <p>
* The default behavior of this method is to defer to the owning {@code FragmentActivity}
* as a {@link FlutterEngineConfigurator}. Subclasses can override this method if the
* subclass needs to override the {@code FragmentActivity}'s behavior, or add to it.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
FragmentActivity attachedActivity = getActivity();
if (attachedActivity instanceof FlutterEngineConfigurator) {
((FlutterEngineConfigurator) attachedActivity).configureFlutterEngine(flutterEngine);
}
}
/**
* See {@link NewEngineFragmentBuilder#shouldAttachEngineToActivity()} and
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate}
*/
@Override
public boolean shouldAttachEngineToActivity() {
return getArguments().getBoolean(ARG_SHOULD_ATTACH_ENGINE_TO_ACTIVITY);
}
/**
* Invoked after the {@link FlutterView} within this {@code FlutterFragment} renders its first
* frame.
* <p>
* This method forwards {@code onFirstFrameRendered()} to its attached {@code Activity}, if
* the attached {@code Activity} implements {@link OnFirstFrameRenderedListener}.
* <p>
* Subclasses that override this method must call through to the {@code super} method.
* <p>
* Used by this {@code FlutterFragment}'s {@link FlutterActivityAndFragmentDelegate.Host}
*/
@Override
public void onFirstFrameRendered() {
FragmentActivity attachedActivity = getActivity();
if (attachedActivity instanceof OnFirstFrameRenderedListener) {
((OnFirstFrameRenderedListener) attachedActivity).onFirstFrameRendered();
}
}
@Override
public void finishContainer(Map<String, Object> result) {
Activity activity= this.getActivity();
activity.finish();
}
@Override
public String getContainerUrl() {
return "flutterFragment";
}
@Override
public Map getContainerUrlParams() {
Map<String,String> params = new HashMap<>();
params.put("aaa","bbb");
return params;
}
/**
* Annotates methods in {@code FlutterFragment} that must be called by the containing
* {@code Activity}.
*/
@interface ActivityCallThrough {
}
}
\ No newline at end of file
...@@ -11,7 +11,6 @@ import android.view.View; ...@@ -11,7 +11,6 @@ import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
import com.idlefish.flutterboost.*; import com.idlefish.flutterboost.*;
import com.idlefish.flutterboost.interfaces.IStateListener;
import io.flutter.Log; import io.flutter.Log;
import io.flutter.embedding.android.FlutterView; import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.android.SplashScreen; import io.flutter.embedding.android.SplashScreen;
...@@ -84,7 +83,7 @@ public class FlutterSplashView extends FrameLayout { ...@@ -84,7 +83,7 @@ public class FlutterSplashView extends FrameLayout {
setSaveEnabled(true); setSaveEnabled(true);
if (mFlutterEngine == null) { if (mFlutterEngine == null) {
mFlutterEngine = NewFlutterBoost.instance().engineProvider().provideEngine(context); mFlutterEngine = NewFlutterBoost.instance().engineProvider();
} }
} }
......
...@@ -4,11 +4,7 @@ package com.idlefish.flutterboost.containers; ...@@ -4,11 +4,7 @@ package com.idlefish.flutterboost.containers;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.Lifecycle; import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner; import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LifecycleRegistry; import android.arch.lifecycle.LifecycleRegistry;
import android.arch.lifecycle.Lifecycle.Event;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.pm.ActivityInfo; import android.content.pm.ActivityInfo;
...@@ -24,8 +20,6 @@ import android.support.annotation.Nullable; ...@@ -24,8 +20,6 @@ import android.support.annotation.Nullable;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import com.idlefish.flutterboost.FlutterBoost;
import com.idlefish.flutterboost.NewFlutterBoost; import com.idlefish.flutterboost.NewFlutterBoost;
import com.idlefish.flutterboost.Utils; import com.idlefish.flutterboost.Utils;
import io.flutter.Log; import io.flutter.Log;
...@@ -554,7 +548,7 @@ public class NewBoostFlutterActivity extends Activity ...@@ -554,7 +548,7 @@ public class NewBoostFlutterActivity extends Activity
@Override @Override
public FlutterEngine provideFlutterEngine(@NonNull Context context) { public FlutterEngine provideFlutterEngine(@NonNull Context context) {
// No-op. Hook for subclasses. // No-op. Hook for subclasses.
return NewFlutterBoost.instance().engineProvider().provideEngine(this); return NewFlutterBoost.instance().engineProvider();
} }
/** /**
...@@ -597,6 +591,25 @@ public class NewBoostFlutterActivity extends Activity ...@@ -597,6 +591,25 @@ public class NewBoostFlutterActivity extends Activity
public void onFirstFrameRendered() { public void onFirstFrameRendered() {
} }
@Override
public void finishContainer(Map<String, Object> result) {
Activity activity= this.getActivity();
activity.finish();
}
@Override
public String getContainerUrl() {
return "flutterPage";
}
@Override
public Map getContainerUrlParams() {
Map<String,String> params = new HashMap<>();
params.put("aaa","bbb");
return params;
}
/** /**
* The mode of the background of a {@code FlutterActivity}, either opaque or transparent. * The mode of the background of a {@code FlutterActivity}, either opaque or transparent.
*/ */
......
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost.interfaces;
import android.content.Context;
import com.idlefish.flutterboost.BoostFlutterEngine;
import io.flutter.embedding.engine.FlutterEngine;
/**
* a flutter engine provider
*/
public interface IFlutterEngineProvider {
/**
* create flutter engine, we just hold a single instance now
* @param context
* @return
*/
FlutterEngine createEngine(Context context);
/**
* provide a flutter engine
* @param context
* @return
*/
FlutterEngine provideEngine(Context context);
/**
* may return null
* @return
*/
FlutterEngine tryGetEngine();
}
...@@ -25,7 +25,6 @@ package com.idlefish.flutterboost.interfaces; ...@@ -25,7 +25,6 @@ package com.idlefish.flutterboost.interfaces;
import android.app.Activity; import android.app.Activity;
import com.idlefish.flutterboost.BoostFlutterView;
import com.idlefish.flutterboost.containers.FlutterSplashView; import com.idlefish.flutterboost.containers.FlutterSplashView;
import java.util.Map; import java.util.Map;
......
...@@ -9,5 +9,4 @@ public interface INativeRouter { ...@@ -9,5 +9,4 @@ public interface INativeRouter {
void openContainer(Context context, String url, Map<String,Object> urlParams, int requestCode, Map<String,Object> exts); void openContainer(Context context, String url, Map<String,Object> urlParams, int requestCode, Map<String,Object> exts);
void closeContainer(IContainerRecord record, Map<String,Object> result, Map<String,Object> exts);
} }
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Alibaba Group
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost.interfaces;
import android.app.Application;
import android.content.Context;
import java.util.Map;
import io.flutter.plugin.common.PluginRegistry;
/**
* APIs that platform(Android App) must provide
*/
public interface IPlatform {
int IMMEDIATELY = 0; //立即启动引擎
int ANY_ACTIVITY_CREATED = 1; //当有任何Activity创建时,启动引擎
/**
* get current application
* @return
*/
Application getApplication();
/**
* debug or not
* @return
*/
boolean isDebug();
/**
* register plugins
* @return
*/
void registerPlugins(PluginRegistry registry);
void openContainer(Context context,String url,Map<String,Object> urlParams,int requestCode,Map<String,Object> exts);
void closeContainer(IContainerRecord record, Map<String,Object> result, Map<String,Object> exts);
IFlutterEngineProvider engineProvider();
/**
* @return
*
* IMMEDIATELY //立即
* ANY_ACTIVITY_CREATED //当有任何Activity创建的时候
* LAZY //懒加载,尽可能延后
*/
int whenEngineStart();
}
package com.idlefish.flutterboost.interfaces;
import com.idlefish.flutterboost.FlutterBoostPlugin;
import com.idlefish.flutterboost.BoostFlutterEngine;
import com.idlefish.flutterboost.BoostFlutterView;
import io.flutter.plugin.common.PluginRegistry;
public interface IStateListener {
void onEngineCreated(BoostFlutterEngine engine);
void onEngineStarted(BoostFlutterEngine engine);
void onChannelRegistered(PluginRegistry.Registrar registrar, FlutterBoostPlugin channel);
void onFlutterViewInited(BoostFlutterEngine engine, BoostFlutterView flutterView);
void beforeEngineAttach(BoostFlutterEngine engine, BoostFlutterView flutterView);
void afterEngineAttached(BoostFlutterEngine engine, BoostFlutterView flutterView);
void beforeEngineDetach(BoostFlutterEngine engine, BoostFlutterView flutterView);
void afterEngineDetached(BoostFlutterEngine engine, BoostFlutterView flutterView);
}
package com.taobao.idlefish.flutterboostexample;
import android.os.Bundle;
import android.support.annotation.Nullable;
import com.idlefish.flutterboost.containers.BoostFlutterFragment;
import com.idlefish.flutterboost.containers.FlutterSplashView;
import java.util.HashMap;
import java.util.Map;
public class FlutterFragment extends BoostFlutterFragment {
@Override
public void setArguments(@Nullable Bundle args) {
if(args == null) {
args = new Bundle();
args.putString("tag","");
}
super.setArguments(args);
}
public void setTabTag(String tag) {
Bundle args = new Bundle();
args.putString("tag",tag);
super.setArguments(args);
}
@Override
public FlutterSplashView getBoostFlutterView() {
return null;
}
@Override
public String getContainerUrl() {
return "flutterFragment";
}
@Override
public Map getContainerUrlParams() {
Map<String,String> params = new HashMap<>();
params.put("tag",getArguments().getString("tag"));
return params;
}
public static FlutterFragment instance(String tag){
FlutterFragment fragment = new FlutterFragment();
fragment.setTabTag(tag);
return fragment;
}
}
...@@ -9,7 +9,7 @@ import android.support.v7.app.AppCompatActivity; ...@@ -9,7 +9,7 @@ import android.support.v7.app.AppCompatActivity;
import android.view.View; import android.view.View;
import android.view.Window; import android.view.Window;
import android.view.WindowManager; import android.view.WindowManager;
import com.idlefish.flutterboost.containers.FlutterFragment;
import io.flutter.plugin.platform.PlatformPlugin; import io.flutter.plugin.platform.PlatformPlugin;
public class FlutterFragmentPageActivity extends AppCompatActivity implements View.OnClickListener { public class FlutterFragmentPageActivity extends AppCompatActivity implements View.OnClickListener {
...@@ -61,16 +61,16 @@ public class FlutterFragmentPageActivity extends AppCompatActivity implements Vi ...@@ -61,16 +61,16 @@ public class FlutterFragmentPageActivity extends AppCompatActivity implements Vi
if(mTab1 == v) { if(mTab1 == v) {
mTab1.setBackgroundColor(Color.YELLOW); mTab1.setBackgroundColor(Color.YELLOW);
mFragment = FlutterFragment.instance("tab1"); mFragment = FlutterFragment.createDefault();
}else if(mTab2 == v) { }else if(mTab2 == v) {
mTab2.setBackgroundColor(Color.YELLOW); mTab2.setBackgroundColor(Color.YELLOW);
mFragment = FlutterFragment.instance("tab2"); mFragment = FlutterFragment.createDefault();
}else if(mTab3 == v) { }else if(mTab3 == v) {
mTab3.setBackgroundColor(Color.YELLOW); mTab3.setBackgroundColor(Color.YELLOW);
mFragment = FlutterFragment.instance("tab3"); mFragment = FlutterFragment.createDefault();
}else{ }else{
mTab4.setBackgroundColor(Color.YELLOW); mTab4.setBackgroundColor(Color.YELLOW);
mFragment = FlutterFragment.instance("tab4"); mFragment = FlutterFragment.createDefault();
} }
getSupportFragmentManager() getSupportFragmentManager()
......
package com.taobao.idlefish.flutterboostexample;
import com.idlefish.flutterboost.containers.BoostFlutterActivity;
import com.idlefish.flutterboost.containers.FlutterSplashView;
import java.util.HashMap;
import java.util.Map;
public class FlutterPageActivity extends BoostFlutterActivity {
@Override
public FlutterSplashView getBoostFlutterView() {
return null;
}
/**
* 该方法返回当前Activity在Flutter层对应的name,
* 混合栈将会在flutter层根据这个名字,在注册的Route表中查找对应的Widget
*
* 在flutter层有注册函数:
* FlutterBoost.singleton.registerPageBuilders({
* 'first': (pageName, params, _) => FirstRouteWidget(),
* 'second': (pageName, params, _) => SecondRouteWidget(),
* ...
* });
*
* 该方法中返回的就是注册的key:first , second
*
* @return
*/
@Override
public String getContainerUrl() {
return "flutterPage";
}
/**
* 该方法返回的参数将会传递给上层的flutter对应的Widget
*
* 在flutter层有注册函数:
* FlutterBoost.singleton.registerPageBuilders({
* 'first': (pageName, params, _) => FirstRouteWidget(),
* 'second': (pageName, params, _) => SecondRouteWidget(),
* ...
* });
*
* 该方法返回的参数就会封装成上面的params
*
* @return
*/
@Override
public Map getContainerUrlParams() {
Map<String,String> params = new HashMap<>();
params.put("aaa","bbb");
return params;
}
}
...@@ -5,7 +5,6 @@ import android.content.Context; ...@@ -5,7 +5,6 @@ import android.content.Context;
import com.idlefish.flutterboost.*; import com.idlefish.flutterboost.*;
import com.idlefish.flutterboost.interfaces.IContainerRecord; import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IFlutterEngineProvider;
import java.util.Map; import java.util.Map;
...@@ -16,48 +15,6 @@ public class MyApplication extends FlutterApplication { ...@@ -16,48 +15,6 @@ public class MyApplication extends FlutterApplication {
@Override @Override
public void onCreate() { public void onCreate() {
super.onCreate(); super.onCreate();
//
// FlutterBoost.init(new Platform() {
//
// @Override
// public Application getApplication() {
// return MyApplication.this;
// }
//
// @Override
// public boolean isDebug() {
// return true;
// }
//
// @Override
// public void openContainer(Context context, String url, Map<String, Object> urlParams, int requestCode, Map<String, Object> exts) {
// PageRouter.openPageByUrl(context, url, urlParams, requestCode);
// }
//
// @Override
// public IFlutterEngineProvider engineProvider() {
// return new BoostEngineProvider() {
// @Override
// public BoostFlutterEngine createEngine(Context context) {
// return new BoostFlutterEngine(context);
// }
// };
// }
//
// @Override
// public int whenEngineStart() {
// return ANY_ACTIVITY_CREATED;
// }
// });
// FlutterBoostPlugin.addActionAfterRegistered(new FlutterBoostPlugin.ActionAfterRegistered() {
// @Override
// public void onChannelRegistered(FlutterBoostPlugin channel) {
// //platform view register should use FlutterPluginRegistry instread of BoostPluginRegistry
// TextPlatformViewPlugin.register(FlutterBoost.singleton().engineProvider().tryGetEngine().getPluginRegistry());
// }
// });
INativeRouter router =new INativeRouter() { INativeRouter router =new INativeRouter() {
@Override @Override
...@@ -65,12 +22,14 @@ public class MyApplication extends FlutterApplication { ...@@ -65,12 +22,14 @@ public class MyApplication extends FlutterApplication {
PageRouter.openPageByUrl(context,url, urlParams); PageRouter.openPageByUrl(context,url, urlParams);
} }
@Override
public void closeContainer(IContainerRecord record, Map<String, Object> result, Map<String, Object> exts) {
}
}; };
Platform platform= new NewFlutterBoost.ConfigBuilder(this,router).build();
Platform platform= new NewFlutterBoost
.ConfigBuilder(this,router)
.isDebug(true)
.whenEngineStart(NewFlutterBoost.ConfigBuilder.ANY_ACTIVITY_CREATED)
.build();
NewFlutterBoost.instance().init(platform); NewFlutterBoost.instance().init(platform);
} }
} }
...@@ -24,7 +24,7 @@ public class PageRouter { ...@@ -24,7 +24,7 @@ public class PageRouter {
context.startActivity( NewBoostFlutterActivity.createDefaultIntent(context)); context.startActivity( NewBoostFlutterActivity.createDefaultIntent(context));
return true; return true;
} else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) { } else if (url.startsWith(FLUTTER_FRAGMENT_PAGE_URL)) {
// context.startActivity(new Intent(context, FlutterFragmentPageActivity.class)); context.startActivity(new Intent(context, FlutterFragmentPageActivity.class));
return true; return true;
} else if (url.startsWith(NATIVE_PAGE_URL)) { } else if (url.startsWith(NATIVE_PAGE_URL)) {
context.startActivity(new Intent(context, NativePageActivity.class)); context.startActivity(new Intent(context, NativePageActivity.class));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment