Commit 00be304b authored by XinLei's avatar XinLei Committed by GitHub

Merge pull request #9 from alibaba/master

[sync] 2020/2/20
parents 22372c09 47c27577
os:
- linux
sudo: false
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++6
# - fonts-droid
before_script:
- git clone https://github.com/flutter/flutter.git -b v1.9.1-hotfixes --depth 1
- ./flutter/bin/flutter doctor
script:
- ./flutter/bin/flutter test --coverage --coverage-path=lcov.info
after_success:
- bash <(curl -s https://codecov.io/bash)
cache:
directories:
- $HOME/.pub-cache
## 1.9.1+1
Rename the version number and start supporting androidx by default, Based on the flutter 1.9.1 - hotfixs。
fixed bugs
## 0.1.66 ## 0.1.66
Fixed bugs Fixed bugs
......
[![Build Status](https://travis-ci.com/alibaba/flutter_boost.svg?branch=master)](https://travis-ci.com/alibaba/flutter_boost) [![pub package](https://img.shields.io/pub/v/flutter_boost.svg)](https://pub.dartlang.org/packages/flutter_boost) [![codecov](https://codecov.io/gh/alibaba/flutter_boost/branch/master/graph/badge.svg)](https://codecov.io/gh/alibaba/flutter_boost)
<p align="center"> <p align="center">
<img src="flutter_boost.png"> <img src="flutter_boost.png">
<b></b><br> <b></b><br>
...@@ -27,9 +29,17 @@ You need to add Flutter to your project before moving on.The version of the flut ...@@ -27,9 +29,17 @@ You need to add Flutter to your project before moving on.The version of the flut
| 0.1.60 | 1.9.1-hotfixes | Android does not support andriodx if other flutter branches will compile incorrectly. | No | | 0.1.60 | 1.9.1-hotfixes | Android does not support andriodx if other flutter branches will compile incorrectly. | No |
| 0.1.61-0.1.69 | 1.9.1-hotfixes | bugfix for 0.1.60. | No | | 0.1.61-0.1.69 | 1.9.1-hotfixes | bugfix for 0.1.60. | No |
| 0.1.63 | 1.9.1-hotfixes | If other branches will compile incorrectly. Synchronize with the 0.1.60 code, and bugfix also merge to this branch. | No | | 0.1.63 | 1.9.1-hotfixes | If other branches will compile incorrectly. Synchronize with the 0.1.60 code, and bugfix also merge to this branch. | No |
| v1.9.1-hotfixes | 1.9.1-hotfixes | Current androidx branch. Please use git to bring in this branch. | Yes | | 1.9.1+1 | 1.9.1-hotfixes | Rename the version number and start supporting androidx by default | Yes |
| Flutter Boost branch | Support Flutter SDK Version | Description | Support AndroidX? |
| --------------------- | --------------------------- | ------------------------------------------------------------ | ------------------ |
| v1.9.1-hotfixes | 1.9.1-hotfixes | for androidx | Yes |
| task/task_v1.9.1_support_hotfixes| 1.9.1-hotfixes | for support | NO |
| v1.12.13-hotfixes | 1.12.13-hotfixes | for androidx | Yes |
| task/task_v1.12.13_support_hotfixes| 1.12.13-hotfixes | for support | NO |
# Getting Started # Getting Started
...@@ -38,19 +48,19 @@ You need to add Flutter to your project before moving on.The version of the flut ...@@ -38,19 +48,19 @@ You need to add Flutter to your project before moving on.The version of the flut
Open you pubspec.yaml and add the following line to dependencies: Open you pubspec.yaml and add the following line to dependencies:
support branch androidx branch
```json ```json
flutter_boost: flutter_boost:
git: git:
url: 'https://github.com/alibaba/flutter_boost.git' url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.1.64' ref: ' 1.9.1+1'
``` ```
androidx branch support branch
```json ```json
flutter_boost: flutter_boost:
git: git:
url: 'https://github.com/alibaba/flutter_boost.git' url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'v0.1.61-androidx-hotfixes' ref: 'task/task_v1.9.1_support_hotfixes'
``` ```
......
...@@ -22,15 +22,25 @@ ...@@ -22,15 +22,25 @@
# boost 版本说明 # boost 版本说明
| Flutter Boost 分支/版本 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? | | Flutter Boost 版本 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? |
| ----------------------- | ----------------------- | ------------------------------------------------------------ | ------------------- | | ----------------------- | ----------------------- | ------------------------------------------------------------ | ------------------- |
| 0.1.50 | 1.5.4-hotfixes | android 如果其他 flutter 版本或者分支会编译错误。 | No | | 0.1.50 | 1.5.4-hotfixes | android 如果其他 flutter 版本或者分支会编译错误。 | No |
| 0.1.51-0.1.59 | 1.5.4-hotfixes | 0.1.50 的 bugfix。 | No | | 0.1.51-0.1.59 | 1.5.4-hotfixes | 0.1.50 的 bugfix。 | No |
| 0.1.60 | 1.9.1-hotfixes | android 如果其他 flutter 分支会编译错误。 | No | | 0.1.60 | 1.9.1-hotfixes | android 如果其他 flutter 分支会编译错误。 | No |
| 0.1.61-0.1.69 | 1.9.1-hotfixes | 0.1.60 的 bugfix。 | No |
| 0.1.63 | 1.9.1-hotfixes | 和 0.1.60 代码同步, bugfix 也会合入该分支,如果其他分支会编译错误。 | No | | 0.1.63 | 1.9.1-hotfixes | 和 0.1.60 代码同步, bugfix 也会合入该分支,如果其他分支会编译错误。 | No |
| v1.9.1-hotfixes | 1.9.1-hotfixes | Current androidx branch.Please use git to bring in this branch. | Yes | | 0.1.61-0.1.69 | 1.9.1-hotfixes | 0.1.60 的 bugfix。 | No |
| 1.9.1+1 | 1.9.1-hotfixes | 版本号重新命名,开始默认支持androidx | Yes |
| Flutter Boost 分支 | 支持的 Flutter SDK 版本 | Description | 是否支持 AndroidX? |
| v1.9.1-hotfixes | 1.9.1-hotfixes | 支持androidx,修复bug后会定期发布新版本 | Yes |
| task/task_v1.9.1_support_hotfixes| 1.9.1-hotfixes | 支持support包,不支持androidx | NO |
| v1.12.13-hotfixes | 1.12.13-hotfixes | 支持androidx,目前还没发布的版本,用分支形式引入 | Yes |
| task/task_v1.12.13_support_hotfixes| 1.12.13-hotfixes | 支持support包,不支持androidx | NO |
.
# 安装 # 安装
...@@ -38,22 +48,19 @@ ...@@ -38,22 +48,19 @@
打开pubspec.yaml并将以下行添加到依赖项: 打开pubspec.yaml并将以下行添加到依赖项:
support分支 androidx branch
```json ```json
flutter_boost: flutter_boost:
git: git:
url: 'https://github.com/alibaba/flutter_boost.git' url: 'https://github.com/alibaba/flutter_boost.git'
ref: '0.1.64' ref: ' 1.9.1+1'
``` ```
support branch
androidx分支
```json ```json
flutter_boost: flutter_boost:
git: git:
url: 'https://github.com/alibaba/flutter_boost.git' url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'v0.1.61-androidx-hotfixes' ref: 'task/task_v1.9.1_support_hotfixes'
``` ```
......
...@@ -8,7 +8,7 @@ buildscript { ...@@ -8,7 +8,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.android.tools.build:gradle:3.2.0'
} }
} }
...@@ -23,11 +23,11 @@ apply plugin: 'com.android.library' ...@@ -23,11 +23,11 @@ apply plugin: 'com.android.library'
android { android {
compileSdkVersion 28 compileSdkVersion 28
buildToolsVersion '27.0.3' buildToolsVersion '28.0.3'
defaultConfig { defaultConfig {
minSdkVersion 16 minSdkVersion 16
targetSdkVersion 28 targetSdkVersion 28
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
lintOptions { lintOptions {
disable 'InvalidPackage' disable 'InvalidPackage'
...@@ -35,11 +35,12 @@ android { ...@@ -35,11 +35,12 @@ android {
} }
dependencies { dependencies {
compileOnly 'com.android.support:appcompat-v7:28.0.0' implementation 'androidx.legacy:legacy-support-v4:1.0.0'
compileOnly 'com.android.support:design:28.0.0' implementation 'com.google.android.material:material:1.0.0'
compileOnly 'com.android.support:support-v4:28.0.0' implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'android.arch.lifecycle:common-java8:1.1.1' implementation 'androidx.annotation:annotation:1.0.0'
compileOnly 'com.alibaba:fastjson:1.2.41' implementation 'androidx.lifecycle:lifecycle-common-java8:2.1.0'
implementation 'com.alibaba:fastjson:1.2.41'
} }
......
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
\ No newline at end of file
...@@ -2,7 +2,7 @@ package com.idlefish.flutterboost; ...@@ -2,7 +2,7 @@ package com.idlefish.flutterboost;
import android.app.Activity; import android.app.Activity;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import io.flutter.Log; import io.flutter.Log;
import io.flutter.embedding.engine.plugins.FlutterPlugin; import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware; import io.flutter.embedding.engine.plugins.activity.ActivityAware;
......
...@@ -5,7 +5,7 @@ import android.app.Activity; ...@@ -5,7 +5,7 @@ import android.app.Activity;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import com.idlefish.flutterboost.interfaces.*; import com.idlefish.flutterboost.interfaces.*;
import io.flutter.embedding.android.FlutterView; import io.flutter.embedding.android.FlutterView;
import io.flutter.embedding.engine.FlutterEngine; import io.flutter.embedding.engine.FlutterEngine;
...@@ -26,6 +26,7 @@ public class FlutterBoost { ...@@ -26,6 +26,7 @@ public class FlutterBoost {
private FlutterEngine mEngine; private FlutterEngine mEngine;
private Activity mCurrentActiveActivity; private Activity mCurrentActiveActivity;
private PluginRegistry mRegistry; private PluginRegistry mRegistry;
private boolean mEnterActivityCreate =false;
static FlutterBoost sInstance = null; static FlutterBoost sInstance = null;
private long FlutterPostFrameCallTime = 0; private long FlutterPostFrameCallTime = 0;
...@@ -56,6 +57,10 @@ public class FlutterBoost { ...@@ -56,6 +57,10 @@ public class FlutterBoost {
@Override @Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
//fix crash:'FlutterBoostPlugin not register yet'
//case: initFlutter after Activity.OnCreate method,and then called start/stop crash
// In SplashActivity ,showDialog(in OnCreate method) to check permission, if authorized, then init sdk and jump homePage)
mEnterActivityCreate = true;
mCurrentActiveActivity = activity; mCurrentActiveActivity = activity;
if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) { if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) {
doInitialFlutter(); doInitialFlutter();
...@@ -70,6 +75,9 @@ public class FlutterBoost { ...@@ -70,6 +75,9 @@ public class FlutterBoost {
@Override @Override
public void onActivityStarted(Activity activity) { public void onActivityStarted(Activity activity) {
if (!mEnterActivityCreate){
return;
}
if (mCurrentActiveActivity == null) { if (mCurrentActiveActivity == null) {
Debuger.log("Application entry foreground"); Debuger.log("Application entry foreground");
...@@ -84,16 +92,24 @@ public class FlutterBoost { ...@@ -84,16 +92,24 @@ public class FlutterBoost {
@Override @Override
public void onActivityResumed(Activity activity) { public void onActivityResumed(Activity activity) {
if (!mEnterActivityCreate){
return;
}
mCurrentActiveActivity = activity; mCurrentActiveActivity = activity;
} }
@Override @Override
public void onActivityPaused(Activity activity) { public void onActivityPaused(Activity activity) {
if (!mEnterActivityCreate){
return;
}
} }
@Override @Override
public void onActivityStopped(Activity activity) { public void onActivityStopped(Activity activity) {
if (!mEnterActivityCreate){
return;
}
if (mCurrentActiveActivity == activity) { if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background"); Debuger.log("Application entry background");
...@@ -108,11 +124,16 @@ public class FlutterBoost { ...@@ -108,11 +124,16 @@ public class FlutterBoost {
@Override @Override
public void onActivitySaveInstanceState(Activity activity, Bundle outState) { public void onActivitySaveInstanceState(Activity activity, Bundle outState) {
if (!mEnterActivityCreate){
return;
}
} }
@Override @Override
public void onActivityDestroyed(Activity activity) { public void onActivityDestroyed(Activity activity) {
if (!mEnterActivityCreate){
return;
}
if (mCurrentActiveActivity == activity) { if (mCurrentActiveActivity == activity) {
Debuger.log("Application entry background"); Debuger.log("Application entry background");
...@@ -141,6 +162,9 @@ public class FlutterBoost { ...@@ -141,6 +162,9 @@ public class FlutterBoost {
if (mEngine != null) return; if (mEngine != null) return;
if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.beforeCreateEngine();
}
FlutterEngine flutterEngine = createEngine(); FlutterEngine flutterEngine = createEngine();
if (mPlatform.lifecycleListener != null) { if (mPlatform.lifecycleListener != null) {
mPlatform.lifecycleListener.onEngineCreated(); mPlatform.lifecycleListener.onEngineCreated();
...@@ -343,6 +367,9 @@ public class FlutterBoost { ...@@ -343,6 +367,9 @@ public class FlutterBoost {
public interface BoostLifecycleListener { public interface BoostLifecycleListener {
void beforeCreateEngine();
void onEngineCreated(); void onEngineCreated();
void onPluginsRegistered(); void onPluginsRegistered();
......
package com.idlefish.flutterboost; package com.idlefish.flutterboost;
import android.support.annotation.Nullable; import android.os.Handler;
import androidx.annotation.Nullable;
import com.idlefish.flutterboost.interfaces.IContainerRecord; import com.idlefish.flutterboost.interfaces.IContainerRecord;
......
...@@ -19,7 +19,6 @@ public abstract class Platform { ...@@ -19,7 +19,6 @@ public abstract class Platform {
public abstract int whenEngineStart(); public abstract int whenEngineStart();
public abstract FlutterView.RenderMode renderMode(); public abstract FlutterView.RenderMode renderMode();
public abstract boolean isDebug(); public abstract boolean isDebug();
...@@ -41,6 +40,14 @@ public abstract class Platform { ...@@ -41,6 +40,14 @@ public abstract class Platform {
if(pluginsRegister!=null){ if(pluginsRegister!=null){
pluginsRegister.registerPlugins(mRegistry); pluginsRegister.registerPlugins(mRegistry);
}else{
try {
Class clz = Class.forName("io.flutter.plugins.GeneratedPluginRegistrant");
Method method = clz.getDeclaredMethod("registerWith", PluginRegistry.class);
method.invoke(null, mRegistry);
} catch (Throwable t) {
Log.i("flutterboost.platform",t.toString());
}
} }
if (lifecycleListener!= null) { if (lifecycleListener!= null) {
......
package com.idlefish.flutterboost; package com.idlefish.flutterboost;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.view.KeyCharacterMap; import android.view.KeyCharacterMap;
import android.view.KeyEvent; import android.view.KeyEvent;
......
...@@ -2,8 +2,8 @@ package com.idlefish.flutterboost; ...@@ -2,8 +2,8 @@ package com.idlefish.flutterboost;
import android.content.Context; import android.content.Context;
import android.graphics.SurfaceTexture; import android.graphics.SurfaceTexture;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.Surface; import android.view.Surface;
import android.view.TextureView; import android.view.TextureView;
......
...@@ -8,11 +8,11 @@ import android.content.res.Configuration; ...@@ -8,11 +8,11 @@ import android.content.res.Configuration;
import android.graphics.Rect; import android.graphics.Rect;
import android.os.Build; import android.os.Build;
import android.os.LocaleList; import android.os.LocaleList;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.annotation.RequiresApi; import androidx.annotation.RequiresApi;
import android.support.annotation.VisibleForTesting; import androidx.annotation.VisibleForTesting;
import android.support.v4.view.ViewCompat; import androidx.core.view.ViewCompat;
import android.text.format.DateFormat; import android.text.format.DateFormat;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.KeyEvent; import android.view.KeyEvent;
......
package com.idlefish.flutterboost; package com.idlefish.flutterboost;
import android.content.Context; import android.content.Context;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.text.Editable; import android.text.Editable;
import android.text.InputType; import android.text.InputType;
import android.text.Selection; import android.text.Selection;
...@@ -191,8 +191,13 @@ public class XTextInputPlugin { ...@@ -191,8 +191,13 @@ public class XTextInputPlugin {
if (isInputConnectionLocked) { if (isInputConnectionLocked) {
return lastInputConnection; return lastInputConnection;
} }
lastInputConnection = platformViewsController.getPlatformViewById(inputTarget.id).onCreateInputConnection(outAttrs); View platformView = platformViewsController.getPlatformViewById(inputTarget.id);
if (platformView != null) {
lastInputConnection = platformView.onCreateInputConnection(outAttrs);
return lastInputConnection; return lastInputConnection;
} else {
return null;
}
} }
outAttrs.inputType = inputTypeFromTextInputType( outAttrs.inputType = inputTypeFromTextInputType(
......
...@@ -2,9 +2,9 @@ package com.idlefish.flutterboost.containers; ...@@ -2,9 +2,9 @@ package com.idlefish.flutterboost.containers;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import android.arch.lifecycle.LifecycleOwner; import androidx.lifecycle.LifecycleOwner;
import android.arch.lifecycle.LifecycleRegistry; import androidx.lifecycle.LifecycleRegistry;
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;
...@@ -15,8 +15,8 @@ import android.graphics.drawable.ColorDrawable; ...@@ -15,8 +15,8 @@ import android.graphics.drawable.ColorDrawable;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.view.*; import android.view.*;
import android.widget.*; import android.widget.*;
import com.idlefish.flutterboost.FlutterBoost; import com.idlefish.flutterboost.FlutterBoost;
......
...@@ -2,14 +2,14 @@ package com.idlefish.flutterboost.containers; ...@@ -2,14 +2,14 @@ package com.idlefish.flutterboost.containers;
import android.annotation.SuppressLint; import android.annotation.SuppressLint;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.graphics.PixelFormat; import android.graphics.PixelFormat;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
......
package com.idlefish.flutterboost.containers; package com.idlefish.flutterboost.containers;
import android.app.Activity; import android.app.Activity;
import android.arch.lifecycle.Lifecycle; import androidx.lifecycle.Lifecycle;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v4.app.Fragment; import androidx.fragment.app.Fragment;
import android.support.v4.app.FragmentActivity; import androidx.fragment.app.FragmentActivity;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
......
...@@ -6,8 +6,8 @@ import android.os.Bundle; ...@@ -6,8 +6,8 @@ import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Parcel; import android.os.Parcel;
import android.os.Parcelable; import android.os.Parcelable;
import android.support.annotation.NonNull; import androidx.annotation.NonNull;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.util.AttributeSet; import android.util.AttributeSet;
import android.view.View; import android.view.View;
import android.widget.FrameLayout; import android.widget.FrameLayout;
......
...@@ -38,7 +38,7 @@ android { ...@@ -38,7 +38,7 @@ android {
targetSdkVersion 28 targetSdkVersion 28
versionCode flutterVersionCode.toInteger() versionCode flutterVersionCode.toInteger()
versionName flutterVersionName versionName flutterVersionName
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
} }
buildTypes { buildTypes {
...@@ -56,11 +56,8 @@ flutter { ...@@ -56,11 +56,8 @@ flutter {
dependencies { dependencies {
testImplementation 'junit:junit:4.12' testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2' androidTestImplementation 'androidx.test:runner:1.1.0'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2' androidTestImplementation 'androidx.test.espresso:espresso-core:3.1.0'
implementation 'com.android.support:appcompat-v7:28.0.0' implementation 'androidx.appcompat:appcompat:1.0.0'
implementation 'com.android.support:design:28.0.0'
implementation 'com.android.support:support-v4:28.0.0'
implementation 'com.alibaba:fastjson:1.2.41'
} }
...@@ -6,9 +6,9 @@ import android.graphics.Color; ...@@ -6,9 +6,9 @@ import android.graphics.Color;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.os.Build; import android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v7.app.ActionBar; import androidx.appcompat.app.ActionBar;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.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;
......
package com.taobao.idlefish.flutterboostexample; package com.taobao.idlefish.flutterboostexample;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
......
package com.taobao.idlefish.flutterboostexample; package com.taobao.idlefish.flutterboostexample;
import android.os.Bundle; import android.os.Bundle;
import android.support.annotation.Nullable; import androidx.annotation.Nullable;
import android.support.v7.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import android.view.View; import android.view.View;
import android.widget.TextView; import android.widget.TextView;
......
...@@ -5,7 +5,7 @@ buildscript { ...@@ -5,7 +5,7 @@ buildscript {
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:3.1.2' classpath 'com.android.tools.build:gradle:3.2.0'
} }
} }
......
org.gradle.jvmargs=-Xmx1536M org.gradle.jvmargs=-Xmx1536M
android.useAndroidX=true
android.enableJetifier=true
\ No newline at end of file
...@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME ...@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.4-all.zip distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
...@@ -30,6 +30,7 @@ class _MyAppState extends State<MyApp> { ...@@ -30,6 +30,7 @@ class _MyAppState extends State<MyApp> {
return FlutterRouteWidget(params:params); return FlutterRouteWidget(params:params);
}, },
}); });
FlutterBoost.singleton.addBoostNavigatorObserver(TestBoostNavigatorObserver());
} }
@override @override
...@@ -44,3 +45,22 @@ class _MyAppState extends State<MyApp> { ...@@ -44,3 +45,22 @@ class _MyAppState extends State<MyApp> {
String pageName, String uniqueId, Map params, Route route, Future _) { String pageName, String uniqueId, Map params, Route route, Future _) {
} }
} }
class TestBoostNavigatorObserver extends NavigatorObserver{
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPush");
}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didPop");
}
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
print("flutterboost#didRemove");
}
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
print("flutterboost#didReplace");
}
}
...@@ -11,7 +11,12 @@ class FirstRouteWidget extends StatelessWidget { ...@@ -11,7 +11,12 @@ class FirstRouteWidget extends StatelessWidget {
title: Text('First Route'), title: Text('First Route'),
), ),
body: Center( body: Center(
child: RaisedButton( child:
Column(
mainAxisAlignment: MainAxisAlignment.center,
children:
<Widget>[
RaisedButton(
child: Text('Open second route'), child: Text('Open second route'),
onPressed: () { onPressed: () {
print("open second page!"); print("open second page!");
...@@ -21,6 +26,19 @@ class FirstRouteWidget extends StatelessWidget { ...@@ -21,6 +26,19 @@ class FirstRouteWidget extends StatelessWidget {
}); });
}, },
), ),
RaisedButton(
child: Text('Present second route'),
onPressed: () {
print("Present second page!");
FlutterBoost.singleton.open("second",urlParams:{"present":true}).then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
],
),
), ),
); );
} }
......
...@@ -53,10 +53,10 @@ ...@@ -53,10 +53,10 @@
}else{ }else{
[_engine runWithEntrypoint:nil]; [_engine runWithEntrypoint:nil];
} }
_dummy = [[FLBFlutterViewContainer alloc] initWithEngine:_engine // _dummy = [[FLBFlutterViewContainer alloc] initWithEngine:_engine
nibName:nil // nibName:nil
bundle:nil]; // bundle:nil];
_dummy.name = kIgnoreMessageWithName; // _dummy.name = kIgnoreMessageWithName;
} }
return self; return self;
...@@ -100,7 +100,7 @@ ...@@ -100,7 +100,7 @@
- (void)atacheToViewController:(FlutterViewController *)vc - (void)atacheToViewController:(FlutterViewController *)vc
{ {
if(_engine.viewController != vc){ if(_engine.viewController != vc){
[(FLBFlutterViewContainer *)_engine.viewController surfaceUpdated:NO]; // [(FLBFlutterViewContainer *)_engine.viewController surfaceUpdated:NO];
_engine.viewController = vc; _engine.viewController = vc;
} }
} }
...@@ -114,8 +114,8 @@ ...@@ -114,8 +114,8 @@
- (void)prepareEngineIfNeeded - (void)prepareEngineIfNeeded
{ {
[(FLBFlutterViewContainer *)_engine.viewController surfaceUpdated:NO]; // [(FLBFlutterViewContainer *)_engine.viewController surfaceUpdated:NO];
NSLog(@"[XDEBUG]---surface changed--reset-"); // NSLog(@"[XDEBUG]---surface changed--reset-");
// [self detach]; // [self detach];
} }
......
...@@ -51,6 +51,9 @@ ...@@ -51,6 +51,9 @@
if(self = [super initWithEngine:FLUTTER_APP.flutterProvider.engine if(self = [super initWithEngine:FLUTTER_APP.flutterProvider.engine
nibName:_flbNibName nibName:_flbNibName
bundle:_flbNibBundle]){ bundle:_flbNibBundle]){
//NOTES:在present页面时,默认是全屏,如此可以触发底层VC的页面事件。否则不会触发而导致异常
self.modalPresentationStyle = UIModalPresentationFullScreen;
[self _setup]; [self _setup];
} }
return self; return self;
...@@ -219,6 +222,13 @@ static NSUInteger kInstanceCounter = 0; ...@@ -219,6 +222,13 @@ static NSUInteger kInstanceCounter = 0;
uniqueId:self.uniqueIDString]; uniqueId:self.uniqueIDString];
[[[UIApplication sharedApplication] keyWindow] endEditing:YES]; [[[UIApplication sharedApplication] keyWindow] endEditing:YES];
[super viewWillDisappear:animated]; [super viewWillDisappear:animated];
//NOTES:因为UIViewController在present view后dismiss其页面的view disappear会发生在下一个页面view appear之后,从而让当前engine持有的vc inactive,此处可驱使其重新resume
if (![self.uniqueIDString isEqualToString:[(FLBFlutterViewContainer*)FLUTTER_VC uniqueIDString]])
{
[FLUTTER_APP resume];
}
} }
...@@ -229,6 +239,14 @@ static NSUInteger kInstanceCounter = 0; ...@@ -229,6 +239,14 @@ static NSUInteger kInstanceCounter = 0;
params:_params params:_params
uniqueId:self.uniqueIDString]; uniqueId:self.uniqueIDString];
[super viewDidDisappear:animated]; [super viewDidDisappear:animated];
//NOTES:因为UIViewController在present view后dismiss其页面的view disappear会发生在下一个页面view appear之后,导致当前engine持有的VC被surfaceUpdate(NO),从而销毁底层的raster。此处是考虑到这种情形,重建surface
if (FLUTTER_VC.beingPresented || self.beingDismissed || ![self.uniqueIDString isEqualToString:[(FLBFlutterViewContainer*)FLUTTER_VC uniqueIDString]])
{
[FLUTTER_APP resume];
[(FLBFlutterViewContainer*)FLUTTER_VC surfaceUpdated:YES];
}
// instead of calling [super viewDidDisappear:animated];, call super's super // instead of calling [super viewDidDisappear:animated];, call super's super
// struct objc_super target = { // struct objc_super target = {
// .super_class = class_getSuperclass([FlutterViewController class]), // .super_class = class_getSuperclass([FlutterViewController class]),
......
...@@ -155,14 +155,11 @@ class BoostContainerState extends NavigatorState { ...@@ -155,14 +155,11 @@ class BoostContainerState extends NavigatorState {
@override @override
void didUpdateWidget(Navigator oldWidget) { void didUpdateWidget(Navigator oldWidget) {
super.didUpdateWidget(oldWidget); super.didUpdateWidget(oldWidget);
findContainerNavigatorObserver(oldWidget)?.removeBoostNavigatorObserver(
FlutterBoost.containerManager.navigatorObserver);
} }
@override @override
void dispose() { void dispose() {
findContainerNavigatorObserver(widget)?.removeBoostNavigatorObserver(
FlutterBoost.containerManager.navigatorObserver);
routerHistory.clear(); routerHistory.clear();
super.dispose(); super.dispose();
} }
...@@ -261,63 +258,52 @@ class ContainerElement extends StatefulElement { ...@@ -261,63 +258,52 @@ class ContainerElement extends StatefulElement {
} }
class ContainerNavigatorObserver extends NavigatorObserver { class ContainerNavigatorObserver extends NavigatorObserver {
BoostNavigatorObserver observer;
final Set<BoostNavigatorObserver> _boostObservers = static final Set<NavigatorObserver> boostObservers =
Set<BoostNavigatorObserver>(); Set<NavigatorObserver>();
ContainerNavigatorObserver(); ContainerNavigatorObserver();
factory ContainerNavigatorObserver.bindContainerManager() => factory ContainerNavigatorObserver.bindContainerManager() =>
ContainerNavigatorObserver() ContainerNavigatorObserver();
..addBoostNavigatorObserver(
FlutterBoost.containerManager.navigatorObserver);
VoidCallback addBoostNavigatorObserver(BoostNavigatorObserver observer) { VoidCallback addBoostNavigatorObserver(NavigatorObserver observer) {
_boostObservers.add(observer); boostObservers.add(observer);
return () => _boostObservers.remove(observer); return () => boostObservers.remove(observer);
} }
void removeBoostNavigatorObserver(BoostNavigatorObserver observer) { void removeBoostNavigatorObserver(NavigatorObserver observer) {
_boostObservers.remove(observer); boostObservers.remove(observer);
} }
@override @override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) { void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
for (BoostNavigatorObserver observer in _boostObservers) { for (NavigatorObserver observer in boostObservers) {
observer.didPush(route, previousRoute); observer.didPush(route, previousRoute);
} }
} }
@override @override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) { void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
for (BoostNavigatorObserver observer in _boostObservers) { for (NavigatorObserver observer in boostObservers) {
observer.didPop(route, previousRoute); observer.didPop(route, previousRoute);
} }
} }
@override @override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) { void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
for (BoostNavigatorObserver observer in _boostObservers) { for (NavigatorObserver observer in boostObservers) {
observer.didRemove(route, previousRoute); observer.didRemove(route, previousRoute);
} }
} }
@override @override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) { void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
for (BoostNavigatorObserver observer in _boostObservers) { for (NavigatorObserver observer in boostObservers) {
observer.didReplace(newRoute: newRoute, oldRoute: oldRoute); observer.didReplace(newRoute: newRoute, oldRoute: oldRoute);
} }
} }
} }
class BoostNavigatorObserver {
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {}
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {}
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {}
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {}
}
...@@ -62,8 +62,6 @@ class BoostContainerManager extends StatefulWidget { ...@@ -62,8 +62,6 @@ class BoostContainerManager extends StatefulWidget {
class ContainerManagerState extends State<BoostContainerManager> { class ContainerManagerState extends State<BoostContainerManager> {
final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>(); final GlobalKey<OverlayState> _overlayKey = GlobalKey<OverlayState>();
final List<BoostContainer> _offstage = <BoostContainer>[]; final List<BoostContainer> _offstage = <BoostContainer>[];
final ManagerNavigatorObserver _navigatorObserver =
ManagerNavigatorObserver();
List<_ContainerOverlayEntry> _leastEntries; List<_ContainerOverlayEntry> _leastEntries;
...@@ -78,7 +76,6 @@ class ContainerManagerState extends State<BoostContainerManager> { ...@@ -78,7 +76,6 @@ class ContainerManagerState extends State<BoostContainerManager> {
bool get foreground => _foreground; bool get foreground => _foreground;
ManagerNavigatorObserver get navigatorObserver => _navigatorObserver;
//Number of containers. //Number of containers.
int get containerCounts => _offstage.length; int get containerCounts => _offstage.length;
...@@ -349,51 +346,3 @@ class _ContainerOverlayEntry extends OverlayEntry { ...@@ -349,51 +346,3 @@ class _ContainerOverlayEntry extends OverlayEntry {
} }
} }
class ManagerNavigatorObserver extends BoostNavigatorObserver {
BoostNavigatorObserver observer;
final Set<BoostNavigatorObserver> _boostObservers =
Set<BoostNavigatorObserver>();
VoidCallback addBoostNavigatorObserver(BoostNavigatorObserver observer) {
_boostObservers.add(observer);
return () => _boostObservers.remove(observer);
}
void removeBoostNavigatorObserver(BoostNavigatorObserver observer) {
_boostObservers.remove(observer);
}
@override
void didPush(Route<dynamic> route, Route<dynamic> previousRoute) {
Logger.log('ManagerNavigatorObserver didPush');
for (BoostNavigatorObserver observer in _boostObservers) {
observer.didPush(route, previousRoute);
}
}
@override
void didPop(Route<dynamic> route, Route<dynamic> previousRoute) {
Logger.log('ManagerNavigatorObserver didPop');
for (BoostNavigatorObserver observer in _boostObservers) {
observer.didPop(route, previousRoute);
}
}
@override
void didRemove(Route<dynamic> route, Route<dynamic> previousRoute) {
Logger.log('ManagerNavigatorObserver didRemove');
for (BoostNavigatorObserver observer in _boostObservers) {
observer.didRemove(route, previousRoute);
}
}
@override
void didReplace({Route<dynamic> newRoute, Route<dynamic> oldRoute}) {
Logger.log('ManagerNavigatorObserver didReplace');
for (BoostNavigatorObserver observer in _boostObservers) {
observer.didReplace(newRoute: newRoute, oldRoute: oldRoute);
}
}
}
...@@ -44,6 +44,7 @@ typedef void PostPushRoute( ...@@ -44,6 +44,7 @@ typedef void PostPushRoute(
String url, String uniqueId, Map params, Route route, Future result); String url, String uniqueId, Map params, Route route, Future result);
class FlutterBoost { class FlutterBoost {
static final FlutterBoost _instance = FlutterBoost(); static final FlutterBoost _instance = FlutterBoost();
final GlobalKey<ContainerManagerState> containerManagerKey = final GlobalKey<ContainerManagerState> containerManagerKey =
GlobalKey<ContainerManagerState>(); GlobalKey<ContainerManagerState>();
...@@ -55,14 +56,23 @@ class FlutterBoost { ...@@ -55,14 +56,23 @@ class FlutterBoost {
static ContainerManagerState get containerManager => static ContainerManagerState get containerManager =>
_instance.containerManagerKey.currentState; _instance.containerManagerKey.currentState;
static void onPageStart() { static TransitionBuilder init(
WidgetsBinding.instance.addPostFrameCallback((_) { {TransitionBuilder builder,
singleton.channel.invokeMethod<Map>('pageOnStart').then((Map pageInfo) { PrePushRoute prePush,
PostPushRoute postPush}) {
if(Platform.isAndroid){
WidgetsBinding.instance.addPostFrameCallback((_){
singleton.channel.invokeMethod<Map>('pageOnStart').then((Map pageInfo){
if (pageInfo == null || pageInfo.isEmpty) return; if (pageInfo == null || pageInfo.isEmpty) return;
if (pageInfo.containsKey("name") && if (pageInfo.containsKey("name") &&
pageInfo.containsKey("params") && pageInfo.containsKey("params") &&
pageInfo.containsKey("uniqueId")) { pageInfo.containsKey("uniqueId")) {
ContainerCoordinator.singleton.nativeContainerDidShow( ContainerCoordinator.singleton.nativeContainerDidShow(
pageInfo["name"], pageInfo["params"], pageInfo["uniqueId"]); pageInfo["name"], pageInfo["params"], pageInfo["uniqueId"]);
} }
...@@ -70,22 +80,6 @@ class FlutterBoost { ...@@ -70,22 +80,6 @@ class FlutterBoost {
}); });
} }
static TransitionBuilder init(
{TransitionBuilder builder,
PrePushRoute prePush,
PostPushRoute postPush}) {
if (Platform.isAndroid) {
onPageStart();
}
assert(() {
() async {
if (Platform.isIOS) {
onPageStart();
}
}();
return true;
}());
return (BuildContext context, Widget child) { return (BuildContext context, Widget child) {
assert(child is Navigator, 'child must be Navigator, what is wrong?'); assert(child is Navigator, 'child must be Navigator, what is wrong?');
...@@ -108,7 +102,7 @@ class FlutterBoost { ...@@ -108,7 +102,7 @@ class FlutterBoost {
BoostChannel get channel => _boostChannel; BoostChannel get channel => _boostChannel;
FlutterBoost() { FlutterBoost(){
ContainerCoordinator(_boostChannel); ContainerCoordinator(_boostChannel);
} }
...@@ -122,29 +116,30 @@ class FlutterBoost { ...@@ -122,29 +116,30 @@ class FlutterBoost {
ContainerCoordinator.singleton.registerPageBuilders(builders); ContainerCoordinator.singleton.registerPageBuilders(builders);
} }
Future<Map<dynamic, dynamic>> open(String url, Future<Map<dynamic,dynamic>> open(String url,{Map<dynamic,dynamic> urlParams,Map<dynamic,dynamic> exts}){
{Map<dynamic, dynamic> urlParams, Map<dynamic, dynamic> exts}) {
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>(); Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
properties["url"] = url; properties["url"] = url;
properties["urlParams"] = urlParams; properties["urlParams"] = urlParams;
properties["exts"] = exts; properties["exts"] = exts;
return channel.invokeMethod<Map<dynamic, dynamic>>('openPage', properties); return channel.invokeMethod<Map<dynamic,dynamic>>(
'openPage', properties);
} }
Future<bool> close(String id, Future<bool> close(String id,{Map<dynamic,dynamic> result,Map<dynamic,dynamic> exts}){
{Map<dynamic, dynamic> result, Map<dynamic, dynamic> exts}) {
assert(id != null); assert(id != null);
BoostContainerSettings settings = containerManager?.onstageSettings; BoostContainerSettings settings = containerManager?.onstageSettings;
Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>(); Map<dynamic, dynamic> properties = new Map<dynamic, dynamic>();
if (exts == null) { if(exts == null){
exts = Map<dynamic, dynamic>(); exts = Map<dynamic,dynamic>();
} }
exts["params"] = settings.params; exts["params"] = settings.params;
if (!exts.containsKey("animated")) { if(!exts.containsKey("animated")){
exts["animated"] = true; exts["animated"] = true;
} }
...@@ -160,30 +155,28 @@ class FlutterBoost { ...@@ -160,30 +155,28 @@ class FlutterBoost {
return channel.invokeMethod<bool>('closePage', properties); return channel.invokeMethod<bool>('closePage', properties);
} }
Future<bool> closeCurrent( Future<bool> closeCurrent({Map<String,dynamic> result,Map<String,dynamic> exts}) {
{Map<String, dynamic> result, Map<String, dynamic> exts}) {
BoostContainerSettings settings = containerManager?.onstageSettings; BoostContainerSettings settings = containerManager?.onstageSettings;
if (exts == null) { if(exts == null){
exts = Map<String, dynamic>(); exts = Map<String,dynamic>();
} }
exts["params"] = settings.params; exts["params"] = settings.params;
if (!exts.containsKey("animated")) { if(!exts.containsKey("animated")){
exts["animated"] = true; exts["animated"] = true;
} }
return close(settings.uniqueId, result: result, exts: exts); return close(settings.uniqueId,result: result,exts: exts);
} }
Future<bool> closeByContext(BuildContext context, Future<bool> closeByContext(BuildContext context,{Map<String,dynamic> result,Map<String,dynamic> exts}) {
{Map<String, dynamic> result, Map<String, dynamic> exts}) {
BoostContainerSettings settings = containerManager?.onstageSettings; BoostContainerSettings settings = containerManager?.onstageSettings;
if (exts == null) { if(exts == null){
exts = Map<String, dynamic>(); exts = Map<String,dynamic>();
} }
exts["params"] = settings.params; exts["params"] = settings.params;
if (!exts.containsKey("animated")) { if(!exts.containsKey("animated")){
exts["animated"] = true; exts["animated"] = true;
} }
return close(settings.uniqueId, result: result, exts: exts); return close(settings.uniqueId,result: result,exts: exts);
} }
///register for Container changed callbacks ///register for Container changed callbacks
...@@ -196,6 +189,8 @@ class FlutterBoost { ...@@ -196,6 +189,8 @@ class FlutterBoost {
_observersHolder.addObserver<BoostContainerLifeCycleObserver>(observer); _observersHolder.addObserver<BoostContainerLifeCycleObserver>(observer);
///register callbacks for Navigators push & pop ///register callbacks for Navigators push & pop
VoidCallback addBoostNavigatorObserver(BoostNavigatorObserver observer) => void addBoostNavigatorObserver(NavigatorObserver observer) =>
_observersHolder.addObserver<BoostNavigatorObserver>(observer); ContainerNavigatorObserver.boostObservers.add(observer);
} }
name: flutter_boost name: flutter_boost
description: 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. description: 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.
version: 0.1.66 version: 1.9.1+1
author: Alibaba Xianyu author: Alibaba Xianyu
homepage: https://github.com/alibaba/flutter_boost homepage: https://github.com/alibaba/flutter_boost
...@@ -12,6 +12,11 @@ dependencies: ...@@ -12,6 +12,11 @@ dependencies:
sdk: flutter sdk: flutter
dev_dependencies:
flutter_test:
sdk: flutter
# For information on the generic Dart part of this file, see the # For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec # following page: https://www.dartlang.org/tools/pub/pubspec
......
import 'package:flutter_test/flutter_test.dart';
import 'unit/boost_channel_test.dart' as boost_channel;
//import 'unit/boost_container_test.dart' as boost_container;
import 'unit/boost_page_route_test.dart' as boost_page_route;
import 'unit/container_coordinator_test.dart'
as container_coordinator;
import 'unit/container_manager_test.dart'
as container_manager;
import 'unit/flutter_boost_test.dart' as flutter_boost;
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
// group('all_test', () {
// boost_channel.main();
//// boost_container.main();
// boost_page_route.main();
// container_coordinator.main();
// container_manager.main();
// flutter_boost.main();
// });
}
import 'package:flutter_boost/channel/boost_channel.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const MethodChannel channel = MethodChannel('flutter_boost');
final List<MethodCall> log = <MethodCall>[];
dynamic response;
channel.setMockMethodCallHandler((MethodCall methodCall) async {
print(methodCall);
log.add(methodCall);
return response;
});
tearDown(() {
log.clear();
});
group('boost_channel', () {
response = null;
test('sendEvent successfully', () async {
Map msg1 = Map();
BoostChannel().sendEvent("name", msg1);
Map msg = Map();
msg["name"] = "name";
msg["arguments"] = msg1;
expect(
log,
<Matcher>[isMethodCall('__event__', arguments: msg)],
);
});
test('invokeMethod successfully', () async {
Map msg = {};
msg["test"] = "test";
BoostChannel().invokeMethod("__event__1", msg);
// expect(e, isException);
expect(
log,
<Matcher>[isMethodCall('__event__1', arguments: msg)],
);
});
test('invokeListMethod successfully', () async {
Map msg = {};
msg["test"] = "test";
var bb = await BoostChannel().invokeListMethod("__event__1", msg);
expect(
log,
<Matcher>[isMethodCall('__event__1', arguments: msg)],
);
});
test('invokeMapMethod successfully', () async {
Map msg = {};
msg["test"] = "test";
BoostChannel().invokeMapMethod("__event__1", msg);
expect(
log,
<Matcher>[isMethodCall('__event__1', arguments: msg)],
);
});
test('invokeMapMethod successfully', () async {
Map msg = {};
msg["test"] = "test";
BoostChannel().invokeMapMethod("__event__1", msg);
expect(
log,
<Matcher>[isMethodCall('__event__1', arguments: msg)],
);
});
test('addEventListener successfully', () async {
Function test = BoostChannel().addEventListener(
"addEventListener", (String name, Map arguments) async => "test");
print("xxx" + test.toString());
expect(
test.toString(),
"Closure: () => Null",
);
});
test('addMethodHandler successfully', () async {
Function test = BoostChannel().addMethodHandler((
MethodCall call) async => "test");
expect(
test.toString(),
"Closure: () => Null",
);
});
});
}
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/container/boost_container.dart';
import 'package:flutter_test/flutter_test.dart';
class FirstWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () {
Navigator.pushNamed(context, '/second');
},
child: Container(
color: const Color(0xFFFFFF00),
child: const Text('X'),
),
);
}
}
class SecondWidget extends StatefulWidget {
@override
SecondWidgetState createState() => SecondWidgetState();
}
class SecondWidgetState extends State<SecondWidget> {
@override
Widget build(BuildContext context) {
return GestureDetector(
onTap: () => Navigator.pop(context),
child: Container(
color: const Color(0xFFFF00FF),
child: const Text('Y'),
),
);
}
}
typedef ExceptionCallback = void Function(dynamic exception);
class ThirdWidget extends StatelessWidget {
const ThirdWidget({this.targetKey, this.onException});
final Key targetKey;
final ExceptionCallback onException;
@override
Widget build(BuildContext context) {
return GestureDetector(
key: targetKey,
onTap: () {
try {
Navigator.of(context);
} catch (e) {
onException(e);
}
},
behavior: HitTestBehavior.opaque,
);
}
}
class OnTapPage extends StatelessWidget {
const OnTapPage({Key key, this.id, this.onTap}) : super(key: key);
final String id;
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: Text('Page $id')),
body: GestureDetector(
onTap: onTap,
behavior: HitTestBehavior.opaque,
child: Container(
child: Center(
child: Text(id, style: Theme.of(context).textTheme.display2),
),
),
),
);
}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('Can navigator navigate to and from a stateful widget',
(WidgetTester tester) async {
final Map<String, WidgetBuilder> routes = <String, WidgetBuilder>{
'/': (BuildContext context) => FirstWidget(), // X
'/second': (BuildContext context) => SecondWidget(), // Y
};
await tester.pumpWidget(MaterialApp(routes: routes));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y', skipOffstage: false), findsNothing);
await tester.tap(find.text('X'));
await tester.pump();
expect(find.text('X'), findsOneWidget);
expect(find.text('Y', skipOffstage: false), isOffstage);
await tester.pump(const Duration(milliseconds: 10));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 10));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 10));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
expect(find.text('X'), findsNothing);
expect(find.text('X', skipOffstage: false), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.tap(find.text('Y'));
expect(find.text('X'), findsNothing);
expect(find.text('Y'), findsOneWidget);
await tester.pump();
await tester.pump();
expect(find.text('X'), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.pump(const Duration(milliseconds: 10));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y'), findsOneWidget);
await tester.pump(const Duration(seconds: 1));
expect(find.text('X'), findsOneWidget);
expect(find.text('Y', skipOffstage: false), findsNothing);
});
//
testWidgets('Navigator.of fails gracefully when not found in context',
(WidgetTester tester) async {
const Key targetKey = Key('foo');
dynamic exception;
final Widget widget = ThirdWidget(
targetKey: targetKey,
onException: (dynamic e) {
exception = e;
},
);
await tester.pumpWidget(widget);
await tester.tap(find.byKey(targetKey));
expect(exception, isInstanceOf<FlutterError>());
expect('$exception',
startsWith('Navigator operation requested with a context'));
});
//
// testWidgets('Navigator.of rootNavigator finds root Navigator',
// (WidgetTester tester) async {
// await tester.pumpWidget(MaterialApp(
// home: Material(
// child: Column(
// children: <Widget>[
// const SizedBox(
// height: 300.0,
// child: Text('Root page'),
// ),
// SizedBox(
// height: 300.0,
// child: Navigator(
// onGenerateRoute: (RouteSettings settings) {
// if (settings.isInitialRoute) {
// return MaterialPageRoute<void>(
// builder: (BuildContext context) {
// return RaisedButton(
// child: const Text('Next'),
// onPressed: () {
// BoostContainer.of(context).push(
// MaterialPageRoute<void>(
// builder: (BuildContext context) {
// return RaisedButton(
// child: const Text('Inner page'),
// onPressed: () {
// BoostContainer.of(context)
// .push(
// MaterialPageRoute<void>(
// builder: (BuildContext context) {
// return const Text('Dialog');
// }),
// );
// },
// );
// }),
// );
// },
// );
// },
// );
// }
// return null;
// },
// ),
// ),
// ],
// ),
// ),
// ));
////
//// await tester.tap(find.text('Next'));
//// await tester.pump();
//// await tester.pump(const Duration(milliseconds: 300));
//
// // Both elements are on screen.
// expect(find.text('Next'), findsOneWidget);
//// expect(tester.getTopLeft(find.text('Inner page')).dy, greaterThan(300.0));
////
//// await tester.tap(find.text('Inner page'));
//// await tester.pump();
//// await tester.pump(const Duration(milliseconds: 300));
////
//// // Dialog is pushed to the whole page and is at the top of the screen, not
//// // inside the inner page.
//// expect(tester.getTopLeft(find.text('Dialog')).dy, 0.0);
// });
}
import 'package:flutter_boost/container/boost_page_route.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('test iOS edge swipe then drop back at starting point works',
(WidgetTester tester) async {
await tester.pumpWidget(
MaterialApp(
theme: ThemeData(platform: TargetPlatform.iOS),
onGenerateRoute: (RouteSettings settings) {
return BoostPageRoute<void>(
settings: settings,
builder: (BuildContext context) {
final String pageNumber = settings.name == '/' ? '1' : '2';
return Center(child: Text('Page $pageNumber'));
},
);
},
),
);
tester.state<NavigatorState>(find.byType(Navigator)).pushNamed('/next');
await tester.pump();
await tester.pump(const Duration(seconds: 1));
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
final TestGesture gesture = await tester.startGesture(const Offset(5, 200));
await gesture.moveBy(const Offset(300, 0));
await tester.pump();
// Bring it exactly back such that there's nothing to animate when releasing.
await gesture.moveBy(const Offset(-300, 0));
await gesture.up();
await tester.pump();
expect(find.text('Page 1'), findsNothing);
expect(find.text('Page 2'), isOnstage);
});
}
import 'package:flutter_boost/container/container_coordinator.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
group('container_coordinator', () {
});
}
\ No newline at end of file
import 'package:flutter_boost/container/container_manager.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/flutter_boost.dart';
final GlobalKey scaffoldKey = GlobalKey();
class FirstRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('First Route'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('First'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
],
),
),
);
}
}
class SecondRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Second Route'),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
RaisedButton(
child: Text('Second'),
onPressed: () {
print("open second page!");
FlutterBoost.singleton.open("second").then((Map value) {
print(
"call me when page is finished. did recieve second route result $value");
});
},
),
],
),
),
);
}
}
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
@override
void initState() {
super.initState();
FlutterBoost.singleton.registerPageBuilders({
'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(),
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Boost example',
key: scaffoldKey,
builder: (BuildContext context, Widget child) {
assert(child is Navigator, 'child must be Navigator, what is wrong?');
final BoostContainerManager manager = BoostContainerManager(
initNavigator: child,
);
return manager;
},
home: Container());
}
void _onRoutePushed(
String pageName, String uniqueId, Map params, Route route, Future _) {}
}
void main() {
TestWidgetsFlutterBinding.ensureInitialized();
testWidgets('test iOS edge swipe then drop back at starting point works',
(WidgetTester tester) async {
await tester.pumpWidget(MyApp());
expect(find.text('First'), findsNothing);
});
}
import 'package:flutter/widgets.dart';
import 'package:flutter_boost/flutter_boost.dart';
import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart';
void main() {
const MethodChannel channel = MethodChannel('flutter_boost');
final List<MethodCall> log = <MethodCall>[];
dynamic response;
channel.setMockMethodCallHandler((MethodCall methodCall) async {
print(methodCall);
log.add(methodCall);
return response;
});
tearDown(() {
log.clear();
});
TestWidgetsFlutterBinding.ensureInitialized();
group('flutter_boost', () {
response = null;
test('init successfully', () async {
Function builder = FlutterBoost.init();
expect(
builder.runtimeType,
TransitionBuilder,
);
});
test('open successfully', () async {
Future<Map<dynamic, dynamic>> result = FlutterBoost.singleton.open("url");
expect(
result,
isInstanceOf<Future<Map<dynamic, dynamic>>>(),
);
});
// test('close successfully', () async {
// Future<bool> result = FlutterBoost.singleton.close("id");
//
// expect(
// result,
// isInstanceOf<bool>(),
// );
// });
});
}
name: boost_test
description: A new Flutter package.
version: 0.0.1
author:
homepage:
environment:
sdk: '>=2.2.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
test: ^1.5.1
dev_dependencies:
flutter_test:
sdk: flutter
flutter_driver:
sdk: flutter
e2e: ^0.2.1
mockito: 4.1.1
flutter_boost:
path: ../
# For information on the generic Dart part of this file, see the
# following page: https://www.dartlang.org/tools/pub/pubspec
# The following section is specific to Flutter.
flutter:
# To add assets to your package, add an assets section, like this:
# assets:
# - images/a_dot_burr.jpeg
# - images/a_dot_ham.jpeg
#
# For details regarding assets in packages, see
# https://flutter.io/assets-and-images/#from-packages
#
# An image asset can refer to one or more resolution-specific "variants", see
# https://flutter.io/assets-and-images/#resolution-aware.
# To add custom fonts to your package, add a fonts section here,
# in this "flutter" section. Each entry in this list should have a
# "family" key with the font family name, and a "fonts" key with a
# list giving the asset and other descriptors for the font. For
# example:
# fonts:
# - family: Schyler
# fonts:
# - asset: fonts/Schyler-Regular.ttf
# - asset: fonts/Schyler-Italic.ttf
# style: italic
# - family: Trajan Pro
# fonts:
# - asset: fonts/TrajanPro.ttf
# - asset: fonts/TrajanPro_Bold.ttf
# weight: 700
#
# For details regarding fonts in packages, see
# https://flutter.io/custom-fonts/#from-packages
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