Commit c06bd5d5 authored by yangwu.jia's avatar yangwu.jia

Merge branch 'master' into develop

# Conflicts:
#	android/src/main/java/com/idlefish/flutterboost/interfaces/IFlutterEngineProvider.java
#	android/src/main/java/com/taobao/idlefish/flutterboost/ContainerRecord.java
#	android/src/main/java/com/taobao/idlefish/flutterboost/containers/FlutterViewStub.java
parents 1d4ba9f8 c45410e2
......@@ -7,4 +7,6 @@
build/
pubspec.lock
.flutter-plugins
\ No newline at end of file
.flutter-plugins
flutter
flutter_boost
## 0.0.1
* TODO: Describe initial release.
## 0.1.5
The main changes are as following:
1. The new version do the page jump (URL route) based on the inherited FlutterViewController or Activity. The jump procedure will create new instance of FlutterView, while the old version just reuse the underlying FlutterView
2. Avoiding keeping and reusing the FlutterView, there is no screenshot and complex attach&detach logical any more. As a result, memory is saved and black or white-screen issue occured in old version all are solved.
3. This version also solved the app life cycle observation issue, we recommend you to use ContainerLifeCycle observer to listen the app enter background or foreground notification instead of WidgetBinding.
4. We did some code refactoring, the main logic became more straightforward.
### API changes
From the point of API changes, we did some refactoring as following:
#### iOS API changes
1. FlutterBoostPlugin's startFlutterWithPlatform function change its parameter from FlutterViewController to Engine
2.
**Before change**
```objectivec
FlutterBoostPlugin
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform onStart:(void (^)(FlutterViewController *))callback;
```
**After change**
```objectivec
FlutterBoostPlugin2
- (void)startFlutterWithPlatform:(id<FLB2Platform>)platform
onStart:(void (^)(id<FlutterBinaryMessenger,
FlutterTextureRegistry,
FlutterPluginRegistry> engine))callback;
```
2. FLBPlatform protocol removed flutterCanPop、accessibilityEnable and added entryForDart
**Before change:**
```objectivec
@protocol FLBPlatform <NSObject>
@optional
//Whether to enable accessibility support. Default value is Yes.
- (BOOL)accessibilityEnable;
// flutter模块是否还可以pop
- (void)flutterCanPop:(BOOL)canpop;
@required
- (void)openPage:(NSString *)name
params:(NSDictionary *)params
animated:(BOOL)animated
completion:(void (^)(BOOL finished))completion;
- (void)closePage:(NSString *)uid
animated:(BOOL)animated
params:(NSDictionary *)params
completion:(void (^)(BOOL finished))completion;
@end
```
**After change:**
```objectivec
@protocol FLB2Platform <NSObject>
@optional
- (NSString *)entryForDart;
@required
- (void)open:(NSString *)url
urlParams:(NSDictionary *)urlParams
exts:(NSDictionary *)exts
completion:(void (^)(BOOL finished))completion;
- (void)close:(NSString *)uid
result:(NSDictionary *)result
exts:(NSDictionary *)exts
completion:(void (^)(BOOL finished))completion;
@end
```
#### Android API changes
Android mainly changed the IPlatform interface and its implementation.
It removed following APIs:
```java
Activity getMainActivity();
boolean startActivity(Context context,String url,int requestCode);
Map getSettings();
```
And added following APIs:
```java
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();
int whenEngineStart();
```
......@@ -5,6 +5,8 @@
<a href="https://mp.weixin.qq.com/s?__biz=MzU4MDUxOTI5NA==&mid=2247484367&idx=1&sn=fcbc485f068dae5de9f68d52607ea08f&chksm=fd54d7deca235ec86249a9e3714ec18be8b2d6dc580cae19e4e5113533a6c5b44dfa5813c4c3&scene=0&subscene=131&clicktime=1551942425&ascene=7&devicetype=android-28&version=2700033b&nettype=ctnet&abtest_cookie=BAABAAoACwASABMABAAklx4AVpkeAMSZHgDWmR4AAAA%3D&lang=zh_CN&pass_ticket=1qvHqOsbLBHv3wwAcw577EHhNjg6EKXqTfnOiFbbbaw%3D&wx_header=1">中文介绍</a>
</p>
Note: Please checkout the release note for the latest 0.1.50 to see changes [0.1.50 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost
A next-generation Flutter-Native hybrid solution. FlutterBoost is a Flutter plugin which enables hybrid integration of Flutter for your existing native apps with minimum efforts.The philosophy of FlutterBoost is to use Flutter as easy as using a WebView. Managing Native pages and Flutter pages at the same time is non-trivial in an existing App. FlutterBoost takes care of page resolution for you. The only thing you need to care about is the name of the page(usually could be an URL). 
<a name="bf647454"></a>
......@@ -20,10 +22,19 @@ You need to add Flutter to your project before moving on.
Open you pubspec.yaml and add the following line to dependencies:
```java
flutter_boost: ^0.0.400
flutter_boost: ^0.0.415
```
or you could rely directly on a Github project tag, for example(recommended)
```java
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.0.415'
```
## Integration with Flutter code.
Add init code to you App
......@@ -61,6 +72,8 @@ class _MyAppState extends State<MyApp> {
## Integration with iOS code.
Note: You need to add libc++ into "Linked Frameworks and Libraries"
Use FLBFlutterAppDelegate as the superclass of your AppDelegate
```objc
......@@ -119,7 +132,7 @@ Initialize FlutterBoost with FLBPlatform at the beginning of your App.
```objc
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
onStart:^(FlutterViewController *fvc) {
onStart:^(id engine) {
}];
```
......@@ -257,5 +270,19 @@ Please see the example for details.
# License
This project is licensed under the MIT License - see the [LICENSE.md](LICENSE.md) file for details
# Acknowledgments
* Flutter
## 关于我们
阿里巴巴-闲鱼技术是国内最早也是最大规模线上运行Flutter的团队。
我们在公众号中为你精选了Flutter独家干货,全面而深入。
内容包括:Flutter的接入、规模化应用、引擎探秘、工程体系、创新技术等教程和开源信息。
**架构/服务端/客户端/前端/算法/质量工程师 在公众号中投递简历,名额不限哦**
欢迎来闲鱼做一个好奇、幸福、有影响力的程序员,简历投递:tino.wjf@alibaba-inc.com
订阅地址
<img src="https://img.alicdn.com/tfs/TB17Ki5XubviK0jSZFNXXaApXXa-656-656.png" width="328px" height="328px">
[For English](https://twitter.com/xianyutech "For English")
......@@ -2,6 +2,9 @@
<img src="flutter_boost.png">
</p>
Note: 请查看最新版本0.1.50的release note 确认变更,[0.1.50 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost
新一代Flutter-Native混合解决方案。 FlutterBoost是一个Flutter插件,它可以轻松地为现有原生应用程序提供Flutter混合集成方案。FlutterBoost的理念是将Flutter像Webview那样来使用。在现有应用程序中同时管理Native页面和Flutter页面并非易事。 FlutterBoost帮你处理页面的映射和跳转,你只需关心页面的名字和参数即可(通常可以是URL)。
......@@ -16,12 +19,17 @@
打开pubspec.yaml并将以下行添加到依赖项:
Release 1.0 之前的版本
```json
flutter_boost: ^0.0.400
flutter_boost: ^0.0.415
```
或者可以直接依赖github的项目的版本,Tag,pub发布会有延迟,推荐直接依赖Github项目
```java
flutter_boost:
git:
url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.0.415'
```
## Dart代码的集成
将init代码添加到App App
......@@ -58,6 +66,8 @@ class _MyAppState extends State<MyApp> {
## iOS代码集成。
注意:需要将libc++ 加入 "Linked Frameworks and Libraries" 中。
使用FLBFlutterAppDelegate作为AppDelegate的超类
```objectivec
......@@ -116,7 +126,7 @@ class _MyAppState extends State<MyApp> {
```的ObjectiveC
[FlutterBoostPlugin.sharedInstance startFlutterWithPlatform:router
onStart:^(FlutterViewController * fvc){
onStart:^(id engine){
}];
```
......@@ -246,12 +256,23 @@ FlutterBoost.singleton.closePageForContext(context);
# Examples
更详细的使用例子请参考Demo
# 作者
阿里巴巴闲鱼终端团队
# 许可证
该项目根据MIT许可证授权 - 有关详细信息,请参阅[LICENSE.md](LICENSE.md)文件
<a name="Acknowledgments"> </a>
# 致谢
- Flutter
## 关于我们
阿里巴巴-闲鱼技术是国内最早也是最大规模线上运行Flutter的团队。
我们在公众号中为你精选了Flutter独家干货,全面而深入。
内容包括:Flutter的接入、规模化应用、引擎探秘、工程体系、创新技术等教程和开源信息。
**架构/服务端/客户端/前端/算法/质量工程师 在公众号中投递简历,名额不限哦**
欢迎来闲鱼做一个好奇、幸福、有影响力的程序员,简历投递:tino.wjf@alibaba-inc.com
订阅地址
<img src="https://img.alicdn.com/tfs/TB17Ki5XubviK0jSZFNXXaApXXa-656-656.png" width="328px" height="328px">
[For English](https://twitter.com/xianyutech "For English")
group 'com.taobao.idlefish.flutterboost'
group 'com.idlefish.flutterboost'
version '1.0-SNAPSHOT'
buildscript {
......@@ -23,7 +23,7 @@ apply plugin: 'com.android.library'
android {
compileSdkVersion 26
buildToolsVersion "26.0.2"
buildToolsVersion '27.0.3'
defaultConfig {
minSdkVersion 16
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
......@@ -37,7 +37,6 @@ dependencies {
implementation 'com.alibaba:fastjson:1.2.41'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:appcompat-v7:26.1.0'
provided rootProject.findProject(":xservice_kit")
}
ext {
......
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.taobao.idlefish.flutterboost">
<application
android:allowBackup="false">
<activity
android:name="com.taobao.idlefish.flutterboost.BoostFlutterActivity"
android:launchMode="standard"
android:screenOrientation="portrait"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|locale|layoutDirection|fontScale|screenLayout|density"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize"/>
</application>
package="com.idlefish.flutterboost">
</manifest>
package com.idlefish.flutterboost;
import android.support.annotation.Nullable;
import com.idlefish.flutterboost.interfaces.IStateListener;
import java.io.Serializable;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
public class BoostChannel {
private static BoostChannel sInstance;
private final MethodChannel mMethodChannel;
private final Set<MethodChannel.MethodCallHandler> mMethodCallHandlers = new HashSet<>();
private final Map<String,Set<EventListener>> mEventListeners = new HashMap<>();
private static final Set<ActionAfterRegistered> sActions = new HashSet<>();
public static BoostChannel singleton() {
if (sInstance == null) {
throw new RuntimeException("BoostChannel not register yet");
}
return sInstance;
}
public static void addActionAfterRegistered(ActionAfterRegistered action) {
if(action == null) return;
if(sInstance == null) {
sActions.add(action);
}else{
action.onChannelRegistered(sInstance);
}
}
public static void registerWith(PluginRegistry.Registrar registrar) {
sInstance = new BoostChannel(registrar);
for(ActionAfterRegistered a : sActions) {
a.onChannelRegistered(sInstance);
}
if(FlutterBoost.sInstance != null) {
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if (stateListener != null) {
stateListener.onChannelRegistered(registrar, sInstance);
}
}
sActions.clear();
}
private BoostChannel(PluginRegistry.Registrar registrar){
mMethodChannel = new MethodChannel(registrar.messenger(), "flutter_boost");
mMethodChannel.setMethodCallHandler(new MethodChannel.MethodCallHandler() {
@Override
public void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
if (methodCall.method.equals("__event__")) {
String name = methodCall.argument("name");
Map args = methodCall.argument("arguments");
Object[] listeners = null;
synchronized (mEventListeners) {
Set<EventListener> set = mEventListeners.get(name);
if (set != null) {
listeners = set.toArray();
}
}
if(listeners != null) {
for(Object o:listeners) {
((EventListener)o).onEvent(name,args);
}
}
}else{
Object[] handlers;
synchronized (mMethodCallHandlers) {
handlers = mMethodCallHandlers.toArray();
}
for(Object o:handlers) {
((MethodChannel.MethodCallHandler)o).onMethodCall(methodCall,result);
}
}
}
});
}
public void invokeMethodUnsafe(final String name,Serializable args){
invokeMethod(name, args, new MethodChannel.Result() {
@Override
public void success(@Nullable Object o) {
//every thing ok...
}
@Override
public void error(String s, @Nullable String s1, @Nullable Object o) {
Debuger.log("invoke method "+name+" error:"+s+" | "+s1);
}
@Override
public void notImplemented() {
Debuger.log("invoke method "+name+" notImplemented");
}
});
}
public void invokeMethod(final String name,Serializable args){
invokeMethod(name, args, new MethodChannel.Result() {
@Override
public void success(@Nullable Object o) {
//every thing ok...
}
@Override
public void error(String s, @Nullable String s1, @Nullable Object o) {
Debuger.exception("invoke method "+name+" error:"+s+" | "+s1);
}
@Override
public void notImplemented() {
Debuger.exception("invoke method "+name+" notImplemented");
}
});
}
public void invokeMethod(final String name,Serializable args,MethodChannel.Result result){
if("__event__".equals(name)) {
Debuger.exception("method name should not be __event__");
}
mMethodChannel.invokeMethod(name, args, result);
}
public void addMethodCallHandler(MethodChannel.MethodCallHandler handler) {
synchronized (mMethodCallHandlers){
mMethodCallHandlers.add(handler);
}
}
public void removeMethodCallHandler(MethodChannel.MethodCallHandler handler) {
synchronized (mMethodCallHandlers) {
mMethodCallHandlers.remove(handler);
}
}
public void addEventListener(String name, EventListener listener) {
synchronized (mEventListeners){
Set<EventListener> set = mEventListeners.get(name);
if(set == null) {
set = new HashSet<>();
}
set.add(listener);
mEventListeners.put(name,set);
}
}
public void removeEventListener(EventListener listener) {
synchronized (mEventListeners) {
for(Set<EventListener> set:mEventListeners.values()) {
set.remove(listener);
}
}
}
public void sendEvent(String name,Map args){
Map event = new HashMap();
event.put("name",name);
event.put("arguments",args);
mMethodChannel.invokeMethod("__event__",event);
}
public interface EventListener {
void onEvent(String name, Map args);
}
public interface ActionAfterRegistered {
void onChannelRegistered(BoostChannel channel);
}
}
/*
* 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.FlutterShellArgs;
import io.flutter.view.FlutterMain;
public class BoostEngineProvider implements IFlutterEngineProvider {
private BoostFlutterEngine mEngine = null;
public BoostEngineProvider() {}
@Override
public BoostFlutterEngine createEngine(Context context) {
return new BoostFlutterEngine(context.getApplicationContext());
}
@Override
public BoostFlutterEngine provideEngine(Context context) {
Utils.assertCallOnMainThread();
if (mEngine == null) {
FlutterShellArgs flutterShellArgs = new FlutterShellArgs(new String[0]);
FlutterMain.ensureInitializationComplete(
context.getApplicationContext(), flutterShellArgs.toArray());
mEngine = createEngine(context.getApplicationContext());
final IStateListener stateListener = FlutterBoost.sInstance.mStateListener;
if(stateListener != null) {
stateListener.onEngineCreated(mEngine);
}
}
return mEngine;
}
@Override
public BoostFlutterEngine tryGetEngine() {
return mEngine;
}
public static void assertEngineRunning(){
final BoostFlutterEngine engine = FlutterBoost.singleton().engineProvider().tryGetEngine();
if(engine == null || !engine.isRunning()) {
throw new RuntimeException("engine is not running yet!");
}
}
}
/*
* 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.Intent;
import com.idlefish.flutterboost.interfaces.IContainerRecord;
import com.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import java.util.HashMap;
import java.util.Map;
public class ContainerRecord implements IContainerRecord {
private final FlutterViewContainerManager mManager;
private final IFlutterViewContainer mContainer;
private final String mUniqueId;
private int mState = STATE_UNKNOW;
private MethodChannelProxy mProxy = new MethodChannelProxy();
ContainerRecord(FlutterViewContainerManager manager, IFlutterViewContainer container) {
final Map params = container.getContainerUrlParams();
if(params != null && params.containsKey(IContainerRecord.UNIQ_KEY)) {
mUniqueId = String.valueOf(params.get(IContainerRecord.UNIQ_KEY));
}else{
mUniqueId = genUniqueId(this);
}
mManager = manager;
mContainer = container;
}
@Override
public String uniqueId() {
return mUniqueId;
}
@Override
public IFlutterViewContainer getContainer() {
return mContainer;
}
@Override
public int getState() {
return mState;
}
@Override
public void onCreate() {
Utils.assertCallOnMainThread();
BoostEngineProvider.assertEngineRunning();
if (mState != STATE_UNKNOW) {
Debuger.exception("state error");
}
mState = STATE_CREATED;
mContainer.getBoostFlutterView().onResume();
mProxy.create();
}
@Override
public void onAppear() {
Utils.assertCallOnMainThread();
if (mState != STATE_CREATED && mState != STATE_DISAPPEAR) {
Debuger.exception("state error");
}
mState = STATE_APPEAR;
mManager.pushRecord(this);
mContainer.getBoostFlutterView().onAttach();
mProxy.appear();
}
@Override
public void onDisappear() {
Utils.assertCallOnMainThread();
if (mState != STATE_APPEAR) {
Debuger.exception("state error");
}
mState = STATE_DISAPPEAR;
mProxy.disappear();
if(getContainer().getContextActivity().isFinishing()) {
mProxy.destroy();
}
mContainer.getBoostFlutterView().onDetach();
mManager.popRecord(this);
}
@Override
public void onDestroy() {
Utils.assertCallOnMainThread();
if (mState != STATE_DISAPPEAR) {
Debuger.exception("state error");
}
mState = STATE_DESTROYED;
mProxy.destroy();
mContainer.getBoostFlutterView().onDestroy();
mManager.removeRecord(this);
mManager.setContainerResult(this,-1,-1,null);
if (!mManager.hasContainerAppear()) {
mContainer.getBoostFlutterView().onPause();
mContainer.getBoostFlutterView().onStop();
}
}
@Override
public void onBackPressed() {
Utils.assertCallOnMainThread();
if (mState == STATE_UNKNOW || mState == STATE_DESTROYED) {
Debuger.exception("state error");
}
HashMap<String, String> map = new HashMap<>();
map.put("type", "backPressedCallback");
map.put("name", mContainer.getContainerUrl());
map.put("uniqueId", mUniqueId);
FlutterBoost.singleton().channel().sendEvent("lifecycle", map);
mContainer.getBoostFlutterView().onBackPressed();
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
mContainer.getBoostFlutterView().onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onNewIntent(Intent intent) {
mContainer.getBoostFlutterView().onNewIntent(intent);
}
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
mContainer.getBoostFlutterView().onActivityResult(requestCode, resultCode, data);
}
@Override
public void onContainerResult(int requestCode, int resultCode, Map<String, Object> result) {
mManager.setContainerResult(this, requestCode,resultCode, result);
}
@Override
public void onUserLeaveHint() {
mContainer.getBoostFlutterView().onUserLeaveHint();
}
@Override
public void onTrimMemory(int level) {
mContainer.getBoostFlutterView().onTrimMemory(level);
}
@Override
public void onLowMemory() {
mContainer.getBoostFlutterView().onLowMemory();
}
private class MethodChannelProxy {
private int mState = STATE_UNKNOW;
private void create() {
if (mState == STATE_UNKNOW) {
invokeChannelUnsafe("didInitPageContainer",
mContainer.getContainerUrl(),
mContainer.getContainerUrlParams(),
mUniqueId
);
//Debuger.log("didInitPageContainer");
mState = STATE_CREATED;
}
}
private void appear() {
invokeChannelUnsafe("didShowPageContainer",
mContainer.getContainerUrl(),
mContainer.getContainerUrlParams(),
mUniqueId
);
//Debuger.log("didShowPageContainer");
mState = STATE_APPEAR;
}
private void disappear() {
if (mState < STATE_DISAPPEAR) {
invokeChannel("didDisappearPageContainer",
mContainer.getContainerUrl(),
mContainer.getContainerUrlParams(),
mUniqueId
);
//Debuger.log("didDisappearPageContainer");
mState = STATE_DISAPPEAR;
}
}
private void destroy() {
if (mState < STATE_DESTROYED) {
invokeChannel("willDeallocPageContainer",
mContainer.getContainerUrl(),
mContainer.getContainerUrlParams(),
mUniqueId
);
//Debuger.log("willDeallocPageContainer");
mState = STATE_DESTROYED;
}
}
public void invokeChannel(String method, String url, Map params, String uniqueId) {
HashMap<String, Object> args = new HashMap<>();
args.put("pageName", url);
args.put("params", params);
args.put("uniqueId", uniqueId);
FlutterBoost.singleton().channel().invokeMethod(method, args);
}
public void invokeChannelUnsafe(String method, String url, Map params, String uniqueId) {
HashMap<String, Object> args = new HashMap<>();
args.put("pageName", url);
args.put("params", params);
args.put("uniqueId", uniqueId);
FlutterBoost.singleton().channel().invokeMethodUnsafe(method, args);
}
}
public static String genUniqueId(Object obj) {
return System.currentTimeMillis() + "-" + obj.hashCode();
}
}
......@@ -21,7 +21,7 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost;
package com.idlefish.flutterboost;
import android.util.Log;
......@@ -60,7 +60,7 @@ public class Debuger {
public static boolean isDebug(){
try {
return FlutterBoostPlugin.platform().isDebug();
return FlutterBoost.singleton().platform().isDebug();
}catch (Throwable t){
return false;
}
......
package com.idlefish.flutterboost;
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.util.Map;
import io.flutter.plugin.common.PluginRegistry;
public abstract class Platform implements IPlatform {
@Override
public boolean isDebug() {
return false;
}
@Override
public void closeContainer(IContainerRecord record, Map<String, Object> result, Map<String, Object> exts) {
if(record == null) return;
record.getContainer().finishContainer(result);
}
@Override
public IFlutterEngineProvider engineProvider() {
return new BoostEngineProvider();
}
@Override
public void registerPlugins(PluginRegistry registry) {
try {
Class clz = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method method = clz.getDeclaredMethod("registerWith",PluginRegistry.class);
method.invoke(null,registry);
}catch (Throwable t){
throw new RuntimeException(t);
}
}
@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, BoostChannel 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");
}
}
package com.idlefish.flutterboost;
import android.app.Activity;
import android.os.Build;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* Created by wangchende on 15-9-7.
*/
public class StatusbarColorUtils {
private static Method mSetStatusBarColorIcon;
private static Method mSetStatusBarDarkIcon;
private static Field mStatusBarColorFiled;
private static int SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = 0;
static {
try {
mSetStatusBarColorIcon = Activity.class.getMethod("setStatusBarDarkIcon", int.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mSetStatusBarDarkIcon = Activity.class.getMethod("setStatusBarDarkIcon", boolean.class);
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
try {
mStatusBarColorFiled = WindowManager.LayoutParams.class.getField("statusBarColor");
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
try {
Field field = View.class.getField("SYSTEM_UI_FLAG_LIGHT_STATUS_BAR");
SYSTEM_UI_FLAG_LIGHT_STATUS_BAR = field.getInt(null);
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
/**
* 判断颜色是否偏黑色
*
* @param color 颜色
* @param level 级别
* @return
*/
public static boolean isBlackColor(int color, int level) {
int grey = toGrey(color);
return grey < level;
}
/**
* 颜色转换成灰度值
*
* @param rgb 颜色
* @return 灰度值
*/
public static int toGrey(int rgb) {
int blue = rgb & 0x000000FF;
int green = (rgb & 0x0000FF00) >> 8;
int red = (rgb & 0x00FF0000) >> 16;
return (red * 38 + green * 75 + blue * 15) >> 7;
}
/**
* 设置状态栏字体图标颜色
*
* @param activity 当前activity
* @param color 颜色
*/
public static void setStatusBarDarkIcon(Activity activity, int color) {
if (mSetStatusBarColorIcon != null) {
try {
mSetStatusBarColorIcon.invoke(activity, color);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
boolean whiteColor = isBlackColor(color, 50);
if (mStatusBarColorFiled != null) {
setStatusBarDarkIcon(activity, whiteColor, whiteColor);
setStatusBarDarkIcon(activity.getWindow(), color);
} else {
setStatusBarDarkIcon(activity, whiteColor);
}
}
}
/**
* 设置状态栏字体图标颜色(只限全屏非activity情况)
*
* @param window 当前窗口
* @param color 颜色
*/
public static void setStatusBarDarkIcon(Window window, int color) {
try {
setStatusBarColor(window, color);
if (Build.VERSION.SDK_INT > 22) {
setStatusBarDarkIcon(window.getDecorView(), true);
}
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 设置状态栏字体图标颜色
*
* @param activity 当前activity
* @param dark 是否深色 true为深色 false 为白色
*/
public static void setStatusBarDarkIcon(Activity activity, boolean dark) {
setStatusBarDarkIcon(activity, dark, true);
}
private static boolean changeMeizuFlag(WindowManager.LayoutParams winParams, String flagName, boolean on) {
try {
Field f = winParams.getClass().getDeclaredField(flagName);
f.setAccessible(true);
int bits = f.getInt(winParams);
Field f2 = winParams.getClass().getDeclaredField("meizuFlags");
f2.setAccessible(true);
int meizuFlags = f2.getInt(winParams);
int oldFlags = meizuFlags;
if (on) {
meizuFlags |= bits;
} else {
meizuFlags &= ~bits;
}
if (oldFlags != meizuFlags) {
f2.setInt(winParams, meizuFlags);
return true;
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (Throwable e) {
e.printStackTrace();
}
return false;
}
/**
* 设置状态栏颜色
*
* @param view
* @param dark
*/
private static void setStatusBarDarkIcon(View view, boolean dark) {
int oldVis = view.getSystemUiVisibility();
int newVis = oldVis;
if (dark) {
newVis |= SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
} else {
newVis &= ~SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
}
if (newVis != oldVis) {
view.setSystemUiVisibility(newVis);
}
}
/**
* 设置状态栏颜色
*
* @param window
* @param color
*/
private static void setStatusBarColor(Window window, int color) {
WindowManager.LayoutParams winParams = window.getAttributes();
if (mStatusBarColorFiled != null) {
try {
int oldColor = mStatusBarColorFiled.getInt(winParams);
if (oldColor != color) {
mStatusBarColorFiled.set(winParams, color);
window.setAttributes(winParams);
}
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
/**
* 设置状态栏字体图标颜色(只限全屏非activity情况)
*
* @param window 当前窗口
* @param dark 是否深色 true为深色 false 为白色
*/
public static void setStatusBarDarkIcon(Window window, boolean dark) {
if (Build.VERSION.SDK_INT < 23) {
changeMeizuFlag(window.getAttributes(), "MEIZU_FLAG_DARK_STATUS_BAR_ICON", dark);
} else {
View decorView = window.getDecorView();
if (decorView != null) {
setStatusBarDarkIcon(decorView, dark);
setStatusBarColor(window, 0);
}
}
}
private static void setStatusBarDarkIcon(Activity activity, boolean dark, boolean flag) {
if (mSetStatusBarDarkIcon != null) {
try {
mSetStatusBarDarkIcon.invoke(activity, dark);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
} else {
if (flag) {
setStatusBarDarkIcon(activity.getWindow(), dark);
}
}
}
}
This diff is collapsed.
/*
* 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);
}
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() {
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() {}
}
......@@ -21,140 +21,138 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost.containers;
package com.idlefish.flutterboost.containers;
import android.content.Context;
import android.graphics.Color;
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.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ProgressBar;
import android.view.Window;
import android.view.WindowManager;
import com.taobao.idlefish.flutterboost.BoostFlutterView;
import com.taobao.idlefish.flutterboost.Debuger;
import com.taobao.idlefish.flutterboost.FlutterBoostPlugin;
import com.taobao.idlefish.flutterboost.interfaces.IFlutterViewContainer;
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.HashMap;
import java.util.Map;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.embedding.android.FlutterView;
import io.flutter.plugin.platform.PlatformPlugin;
abstract public class BoostFlutterFragment extends Fragment implements IFlutterViewContainer {
FlutterContent mContent;
PluginRegistry mRegistry;
boolean resumed = false;
protected BoostFlutterEngine mFlutterEngine;
protected BoostFlutterView mFlutterView;
protected IOperateSyncer mSyncer;
@Nullable
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
mSyncer = FlutterBoost.singleton().containerManager().generateSyncer(this);
mFlutterEngine = createFlutterEngine();
mFlutterView = createFlutterView(mFlutterEngine);
mSyncer.onCreate();
mRegistry = FlutterBoostPlugin.containerManager().onContainerCreate(this);
onRegisterPlugins(mRegistry);
return mFlutterView;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
mContent = new FlutterContent(getActivity());
return mContent;
protected BoostFlutterEngine createFlutterEngine(){
return FlutterBoost.singleton().engineProvider().provideEngine(getContext());
}
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();
if (!resumed) {
resumed = true;
FlutterBoostPlugin.containerManager().onContainerAppear(this);
mContent.attachFlutterView(getBoostFlutterView());
Log.e("FlutterBoost", "FlutterMenuFragment resume");
}
mSyncer.onAppear();
mFlutterEngine.getLifecycleChannel().appIsResumed();
}
@Override
public void onPause() {
mSyncer.onDisappear();
super.onPause();
if (resumed) {
resumed = false;
mContent.snapshot();
FlutterBoostPlugin.containerManager().onContainerDisappear(this);
Log.e("FlutterBoost", "FlutterMenuFragment stop");
}
mFlutterEngine.getLifecycleChannel().appIsInactive();
}
@Override
public void onDestroy() {
mSyncer.onDestroy();
super.onDestroy();
if (mContent != null) {
mContent.destroy();
}
FlutterBoostPlugin.containerManager().onContainerDestroy(this);
}
@Override
public void onContainerShown() {
mContent.onContainerShown();
public void onBackPressed() {
mSyncer.onBackPressed();
}
@Override
public void onContainerHidden() {
mContent.onContainerHidden();
public void onNewIntent(Intent intent) {
mSyncer.onNewIntent(intent);
}
@Override
public BoostFlutterView getBoostFlutterView() {
return FlutterBoostPlugin.viewProvider().createFlutterView(this);
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mSyncer.onActivityResult(requestCode,resultCode,data);
}
@Override
public boolean isFinishing() {
return getActivity().isFinishing();
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
mSyncer.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
protected View createSplashScreenView() {
FrameLayout layout = new FrameLayout(getContext());
FrameLayout.LayoutParams params = new FrameLayout.LayoutParams(
ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
params.gravity = Gravity.CENTER;
layout.addView(new ProgressBar(getContext()),params);
return layout;
public void onTrimMemory(int level) {
mSyncer.onTrimMemory(level);
}
protected View createFlutterInitCoverView() {
View initCover = new View(getActivity());
initCover.setBackgroundColor(Color.WHITE);
return initCover;
@Override
public void onLowMemory() {
super.onLowMemory();
mSyncer.onLowMemory();
}
@Override
public void setBoostResult(HashMap result) {
public void onUserLeaveHint() {
mSyncer.onUserLeaveHint();
}
class FlutterContent extends FlutterViewStub {
@Override
public Activity getContextActivity() {
return getActivity();
}
public FlutterContent(Context context) {
super(context);
}
@Override
public BoostFlutterView getBoostFlutterView() {
return mFlutterView;
}
@Override
public View createFlutterInitCoverView() {
return BoostFlutterFragment.this.createFlutterInitCoverView();
}
@Override
public void finishContainer(Map<String,Object> result) {
getFragmentManager().popBackStack();
}
@Override
public BoostFlutterView getBoostFlutterView() {
return BoostFlutterFragment.this.getBoostFlutterView();
}
@Override
public void onContainerShown() {}
@Override
public View createSplashScreenView() {
return BoostFlutterFragment.this.createSplashScreenView();
}
}
@Override
public void onContainerHidden() {}
}
......@@ -21,22 +21,17 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.idlefish.flutterboost.interfaces;
#import "FLBViewProviderFactory.h"
#import "FLBFlutterEngine.h"
#import "FLBFlutterEngineOld.h"
public interface IContainerManager {
IOperateSyncer generateSyncer(IFlutterViewContainer container);
IContainerRecord getCurrentTopRecord();
@implementation FLBViewProviderFactory
IContainerRecord getLastGenerateRecord();
- (id<FLBFlutterViewProvider>)createViewProvider
{
#if RELEASE_1_0
return [FLBFlutterEngine new];
#else
return [FLBFlutterEngineOld new];
#endif
}
IFlutterViewContainer findContainerById(String uniqueId);
@end
boolean hasContainerAppear();
}
\ No newline at end of file
......@@ -21,14 +21,15 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost.interfaces;
import java.util.Map;
package com.idlefish.flutterboost.interfaces;
/**
* a container record, which use map a flutter page
*/
public interface IContainerRecord {
public interface IContainerRecord extends IOperateSyncer{
String UNIQ_KEY = "__container_uniqueId_key__";
int STATE_UNKNOW = 0;
int STATE_CREATED = 1;
int STATE_APPEAR = 2;
......@@ -38,9 +39,4 @@ public interface IContainerRecord {
String uniqueId();
IFlutterViewContainer getContainer();
int getState();
void onCreate();
void onAppear();
void onDisappear();
void onDestroy();
void onResult(Map Result);
}
......@@ -21,32 +21,33 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost;
package com.idlefish.flutterboost.interfaces;
import android.content.Context;
import io.flutter.view.FlutterNativeView;
public class BoostFlutterNativeView extends FlutterNativeView {
public BoostFlutterNativeView(Context context) {
super(context);
}
public void detachFromFlutterView() {
//do nothing...
}
public void detach() {
//do nothing...
}
@Override
public void destroy() {
//do nothing...
}
public void boostDestroy() {
super.destroy();
}
import com.idlefish.flutterboost.BoostFlutterEngine;
/**
* a flutter engine provider
*/
public interface IFlutterEngineProvider {
/**
* create flutter engine, we just hold a single instance now
* @param context
* @return
*/
BoostFlutterEngine createEngine(Context context);
/**
* provide a flutter engine
* @param context
* @return
*/
BoostFlutterEngine provideEngine(Context context);
/**
* may return null
* @return
*/
BoostFlutterEngine tryGetEngine();
}
......@@ -21,15 +21,13 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost.interfaces;
package com.idlefish.flutterboost.interfaces;
import android.app.Activity;
import com.taobao.idlefish.flutterboost.BoostFlutterView;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;
import io.flutter.plugin.common.PluginRegistry;
import com.idlefish.flutterboost.BoostFlutterView;
import java.util.Map;
/**
* a container which contains the flutter view
......@@ -37,7 +35,7 @@ import io.flutter.plugin.common.PluginRegistry;
public interface IFlutterViewContainer {
String RESULT_KEY = "_flutter_result_";
Activity getActivity();
Activity getContextActivity();
/**
* provide a flutter view
......@@ -48,19 +46,19 @@ public interface IFlutterViewContainer {
/**
* call to destroy the container
*/
void destroyContainer();
void finishContainer(Map<String,Object> result);
/**
* container name
* @return
*/
String getContainerName();
String getContainerUrl();
/**
* container params
* @return
*/
Map getContainerParams();
Map getContainerUrlParams();
/**
* callback when container shown
......@@ -71,22 +69,4 @@ public interface IFlutterViewContainer {
* callback when container hidden
*/
void onContainerHidden();
/**
* is container finishing
* @return
*/
boolean isFinishing();
/**
* call by flutter side to set result
* @param result
*/
void setBoostResult(HashMap result);
/**
* register flutter plugins
* @param registry
*/
void onRegisterPlugins(PluginRegistry registry);
}
package com.idlefish.flutterboost.interfaces;
import android.content.Intent;
import java.util.Map;
public interface IOperateSyncer {
void onCreate();
void onAppear();
void onDisappear();
void onDestroy();
void onBackPressed();
void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults);
void onNewIntent(Intent intent);
void onActivityResult(int requestCode, int resultCode, Intent data);
void onContainerResult(int requestCode, int resultCode, Map<String,Object> result);
void onUserLeaveHint();
void onTrimMemory(int level);
void onLowMemory();
}
......@@ -21,31 +21,29 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package com.taobao.idlefish.flutterboost.interfaces;
package com.idlefish.flutterboost.interfaces;
import android.app.Activity;
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();
/**
* get main activity, which must always exist at the bottom of task stack.
* @return
*/
Activity getMainActivity();
/**
* debug or not
* @return
......@@ -53,18 +51,25 @@ public interface IPlatform {
boolean isDebug();
/**
* start a new activity from flutter page, you may need a page router with url
* @param context
* @param url
* @param requestCode
* register plugins
* @return
*/
boolean startActivity(Context context,String url,int requestCode);
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();
/**
* settings, no use
* @return
*
* IMMEDIATELY //立即
* ANY_ACTIVITY_CREATED //当有任何Activity创建的时候
* LAZY //懒加载,尽可能延后
*/
Map getSettings();
int whenEngineStart();
}
package com.idlefish.flutterboost.interfaces;
import com.idlefish.flutterboost.BoostChannel;
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, BoostChannel 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);
}
/*
* 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.taobao.idlefish.flutterboost;
import android.content.Context;
import android.graphics.Bitmap;
import android.os.Build;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.WindowInsets;
import com.taobao.idlefish.flutterboost.NavigationService.NavigationService;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import io.flutter.view.FlutterNativeView;
import io.flutter.view.FlutterView;
public class BoostFlutterView extends FlutterView {
private boolean mFirstFrameCalled = false;
private boolean mResumed = false;
private WindowInsets mCurrentWindowInsets;
private BoostCallback mBoostCallback;
public BoostFlutterView(Context context, AttributeSet attrs, FlutterNativeView nativeView) {
super(context, attrs, nativeView);
super.addFirstFrameListener(new FirstFrameListener() {
@Override
public void onFirstFrame() {
mFirstFrameCalled = true;
}
});
try {
Field field = FlutterView.class.getDeclaredField("mSurfaceCallback");
field.setAccessible(true);
SurfaceHolder.Callback cb = (SurfaceHolder.Callback)field.get(this);
getHolder().removeCallback(cb);
mBoostCallback = new BoostCallback(cb);
getHolder().addCallback(mBoostCallback);
}catch (Throwable t){
Debuger.exception(t);
}
}
@Override
public void onStart() {
//do nothing...
}
@Override
public void onPostResume() {
//do nothing...
requestFocus();
}
@Override
public void onPause() {
//do nothing...
}
@Override
public void onStop() {
//do nothing...
}
@Override
public FlutterNativeView detach() {
//do nothing...
return getFlutterNativeView();
}
@Override
public void destroy() {
//do nothing...
}
@Override
public Bitmap getBitmap() {
if(getFlutterNativeView() == null || !getFlutterNativeView().isAttached()) {
Debuger.exception("FlutterView not attached!");
return null;
}
return super.getBitmap();
}
public boolean firstFrameCalled() {
return mFirstFrameCalled;
}
public void boostResume() {
if (!mResumed) {
mResumed = true;
super.onPostResume();
Debuger.log("resume flutter view");
}
}
public void boostStop() {
if (mResumed) {
super.onStop();
Debuger.log("stop flutter view");
mResumed = false;
}
}
public boolean isResumed() {
return mResumed;
}
public void boostDestroy() {
super.destroy();
}
public void scheduleFrame(){
if (mResumed) {
Map<String,String> map = new HashMap<>();
map.put("type","scheduleFrame");
NavigationService.getService().emitEvent(map);
}
}
class BoostCallback implements SurfaceHolder.Callback {
final SurfaceHolder.Callback mCallback;
BoostCallback(SurfaceHolder.Callback cb){
this.mCallback = cb;
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
//Debuger.log("flutterView surfaceCreated");
try {
mCallback.surfaceCreated(holder);
}catch (Throwable t){
Debuger.exception(t);
}
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
//Debuger.log("flutterView surfaceChanged");
try {
mCallback.surfaceChanged(holder,format,width,height);
scheduleFrame();
}catch (Throwable t){
Debuger.exception(t);
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
//Debuger.log("flutterView surfaceDestroyed");
try {
mCallback.surfaceDestroyed(holder);
}catch (Throwable t){
Debuger.exception(t);
}
}
}
@Override
protected void onAttachedToWindow() {
//Debuger.log("flutterView onAttachedToWindow");
super.onAttachedToWindow();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
final WindowInsets windowInsets = getRootWindowInsets();
if(windowInsets != null) {
if(mCurrentWindowInsets == null ||
!TextUtils.equals(windowInsets.toString(),mCurrentWindowInsets.toString())) {
Debuger.log("setWindowInsets "+windowInsets.toString());
mCurrentWindowInsets = windowInsets;
super.onApplyWindowInsets(mCurrentWindowInsets);
}
}
}
}
}
/*
* 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.taobao.idlefish.flutterboost;
import android.os.Handler;
import com.taobao.idlefish.flutterboost.NavigationService.NavigationService;
import com.taobao.idlefish.flutterboost.interfaces.IContainerManager;
import com.taobao.idlefish.flutterboost.interfaces.IContainerRecord;
import com.taobao.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import java.util.Map;
import fleamarket.taobao.com.xservicekit.handler.MessageResult;
public class ContainerRecord implements IContainerRecord {
private final IContainerManager mManager;
private final IFlutterViewContainer mContainer;
private final String mUniqueId;
private final Handler mHandler = new Handler();
private int mState = STATE_UNKNOW;
private MethodChannelProxy mProxy = new MethodChannelProxy();
public ContainerRecord(IContainerManager manager, IFlutterViewContainer container) {
mUniqueId = System.currentTimeMillis() + "-" + hashCode();
mManager = manager;
mContainer = container;
}
@Override
public String uniqueId() {
return mUniqueId;
}
@Override
public IFlutterViewContainer getContainer() {
return mContainer;
}
@Override
public int getState() {
return mState;
}
@Override
public void onCreate() {
mState = STATE_CREATED;
mContainer.getBoostFlutterView().boostResume();
mProxy.create();
}
@Override
public void onAppear() {
mState = STATE_APPEAR;
mContainer.getBoostFlutterView().boostResume();
mProxy.appear();
}
@Override
public void onDisappear() {
mProxy.disappear();
mState = STATE_DISAPPEAR;
/**
* Bug workaround:
* If current container is finishing, we should call destroy flutter page early.
*/
if(mContainer.isFinishing()) {
mHandler.post(new Runnable() {
@Override
public void run() {
mProxy.destroy();
}
});
}
}
@Override
public void onDestroy() {
mProxy.destroy();
mState = STATE_DESTROYED;
}
@Override
public void onResult(Map Result) {
NavigationService.onNativePageResult(
genResult("onNativePageResult"),
mUniqueId,
mUniqueId,
Result,
mContainer.getContainerParams()
);
}
private class MethodChannelProxy {
private int mState = STATE_UNKNOW;
private void create() {
if (mState == STATE_UNKNOW) {
NavigationService.didInitPageContainer(
genResult("didInitPageContainer"),
mContainer.getContainerName(),
mContainer.getContainerParams(),
mUniqueId
);
//Debuger.log("didInitPageContainer");
mState = STATE_CREATED;
}
}
private void appear() {
NavigationService.didShowPageContainer(
genResult("didShowPageContainer"),
mContainer.getContainerName(),
mContainer.getContainerParams(),
mUniqueId
);
//Debuger.log("didShowPageContainer");
mState = STATE_APPEAR;
}
private void disappear() {
if (mState < STATE_DISAPPEAR) {
NavigationService.didDisappearPageContainer(
genResult("didDisappearPageContainer"),
mContainer.getContainerName(),
mContainer.getContainerParams(),
mUniqueId
);
//Debuger.log("didDisappearPageContainer");
mState = STATE_DISAPPEAR;
}
}
private void destroy() {
if (mState < STATE_DESTROYED) {
NavigationService.willDeallocPageContainer(
genResult("willDeallocPageContainer"),
mContainer.getContainerName(),
mContainer.getContainerParams(),
mUniqueId
);
//Debuger.log("willDeallocPageContainer");
mState = STATE_DESTROYED;
}
}
}
private MessageResult<Boolean> genResult(final String name) {
return new MessageResult<Boolean>() {
@Override
public void success(Boolean var1) {
//Debuger.log(name + " call success");
}
@Override
public void error(String var1, String var2, Object var3) {
Debuger.log(name + " call error");
}
@Override
public void notImplemented() {
Debuger.log(name + " call not Impelemented");
}
};
}
}
/*
* 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.taobao.idlefish.flutterboost;
import android.app.Activity;
import com.taobao.idlefish.flutterboost.interfaces.IFlutterViewContainer;
import com.taobao.idlefish.flutterboost.interfaces.IFlutterViewProvider;
import com.taobao.idlefish.flutterboost.interfaces.IPlatform;
public class FlutterViewProvider implements IFlutterViewProvider {
private final IPlatform mPlatform;
private BoostFlutterNativeView mFlutterNativeView = null;
private BoostFlutterView mFlutterView = null;
FlutterViewProvider(IPlatform platform){
mPlatform = platform;
}
@Override
public BoostFlutterView createFlutterView(IFlutterViewContainer container) {
Activity activity = mPlatform.getMainActivity();
if(activity == null) {
Debuger.log("create Flutter View not with MainActivity");
activity = container.getActivity();
}
if (mFlutterView == null) {
mFlutterView = new BoostFlutterView(activity, null, createFlutterNativeView(container));
}
return mFlutterView;
}
@Override
public BoostFlutterNativeView createFlutterNativeView(IFlutterViewContainer container) {
if (mFlutterNativeView == null) {
mFlutterNativeView = new BoostFlutterNativeView(container.getActivity().getApplicationContext());
}
return mFlutterNativeView;
}
@Override
public BoostFlutterView tryGetFlutterView() {
return mFlutterView;
}
@Override
public void stopFlutterView() {
final BoostFlutterView view = mFlutterView;
if(view != null) {
view.boostStop();
}
}
@Override
public void reset() {
if(mFlutterNativeView != null) {
mFlutterNativeView.boostDestroy();
mFlutterNativeView = null;
}
if(mFlutterView != null) {
mFlutterView.boostDestroy();
mFlutterView = null;
}
}
}
/*
* 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.taobao.idlefish.flutterboost;
import com.taobao.idlefish.flutterboost.interfaces.IContainerRecord;
import com.taobao.idlefish.flutterboost.interfaces.IContainerManager;
public class Instrument {
private final IContainerManager mManager;
Instrument(IContainerManager manager) {
mManager = manager;
}
public void performCreate(IContainerRecord record) {
final int currentState = record.getState();
if (currentState != IContainerRecord.STATE_UNKNOW) {
Debuger.exception("performCreate state error, current state:" + currentState);
return;
}
record.onCreate();
}
public void performAppear(IContainerRecord record) {
final int currentState = record.getState();
if (currentState != IContainerRecord.STATE_CREATED
&& currentState != IContainerRecord.STATE_DISAPPEAR) {
Debuger.exception("performAppear state error, current state:" + currentState);
return;
}
record.onAppear();
}
public void performDisappear(IContainerRecord record) {
final int currentState = record.getState();
if (currentState != IContainerRecord.STATE_APPEAR) {
Debuger.exception("performDisappear state error , current state:" + currentState);
return;
}
record.onDisappear();
}
public void performDestroy(IContainerRecord record) {
final int currentState = record.getState();
if (currentState != IContainerRecord.STATE_DISAPPEAR) {
Debuger.exception("performDestroy state error, current state:" + currentState);
}
record.onDestroy();
}
}
/*
* 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.taobao.idlefish.flutterboost.NavigationService;
public class NavigationServiceRegister {
public static void register(){
NavigationService.register();
NavigationService_onShownContainerChanged.register();
NavigationService_onFlutterPageResult.register();
NavigationService_pageOnStart.register();
NavigationService_openPage.register();
NavigationService_closePage.register();
}
}
\ 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.taobao.idlefish.flutterboost;
import java.util.Map;
public interface PageResultHandler {
void onResult(String key , Map resultData);
}
......@@ -25,7 +25,7 @@ apply plugin: 'com.android.application'
apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
android {
compileSdkVersion 27
compileSdkVersion 26
lintOptions {
disable 'InvalidPackage'
......@@ -35,7 +35,7 @@ android {
// TODO: Specify your own unique Application ID (https://developer.android.com/studio/build/application-id.html).
applicationId "com.taobao.idlefish.flutterboostexample"
minSdkVersion 16
targetSdkVersion 27
targetSdkVersion 26
versionCode flutterVersionCode.toInteger()
versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
......@@ -58,6 +58,6 @@ dependencies {
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-v4:26.1.0'
implementation 'com.android.support:appcompat-v7:26.1.0'
}
/Users/jidong/Documents/FlutterBoost
\ No newline at end of file
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
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