Commit a558f1e3 authored by XinLei's avatar XinLei Committed by GitHub

Merge pull request #7 from alibaba/master

sync 2020/1/1
parents f02db485 81925f8e
---
name: Bug report
about: Describe this issue template's purpose here.
title: ''
labels: ''
assignees: ''
---
<!-- Thank you for using Flutter Boost!
If you are looking for support about how to get start, please read README first
-->
## Steps to Reproduce
**A small application to reproduce the bug(最小化可复现的demo)**
<!--
Please tell us exactly how to reproduce the problem you are running into.
Please attach a small application (ideally just one main.dart file) that
reproduces the problem. You could use https://gist.github.com/ for this.
If the problem is with your application's rendering, then please attach
a screenshot and explain what the problem is.
-->
1. ...
2. ...
3. ...
<!--
Please tell us which target platform(s) the problem occurs (Android / iOS / Web / macOS / Linux / Windows)
Which target OS version, for Web, browser, is the test system running?
Does the problem occur on emulator/simulator as well as on physical devices?
-->
**Flutter Boost Version**
**Target Platform:**
**Target OS version/browser:**
**Devices:**
## Logs
add your crash log or something else.
<!-- Finally, paste the output of running `flutter doctor -v` here. -->
```
```
# Configuration for probot-no-response - https://github.com/probot/no-response
# Number of days of inactivity before an Issue is closed for lack of response
daysUntilClose: 21
# Label requiring a response
responseRequiredLabel: more-information-needed
# Comment to post when closing an Issue for lack of response. Set to `false` to disable
closeComment: >
This issue has been automatically closed because there has been no response
to our request for more information from the original author. With only the
information that is currently in the issue, we don't have enough information
to take action. Please reach out if you have or find the answers we need so
that we can investigate further.
Thanks for your contribution.
## 0.0.1 ## 0.1.64
* TODO: Describe initial release. Fixed bugs
## 0.1.5
The main changes are as following: ## 0.1.63
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.
android:
Fixed bugs
iOS:
no change
## 0.1.61
android:
Fixed bugs
iOS:
no change
## 0.1.60 ## 0.1.60
...@@ -30,13 +39,19 @@ ios: ...@@ -30,13 +39,19 @@ ios:
1.based on the v1.9.1+hotfixes branch of flutter 1.based on the v1.9.1+hotfixes branch of flutter
2.bugfixed 2.bugfixed
## 0.1.61
android:
Fixed bugs
iOS: ## 0.1.5
no change 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.
## 0.0.1
* TODO: Describe initial release.
### API changes ### API changes
From the point of API changes, we did some refactoring as following: From the point of API changes, we did some refactoring as following:
......
### 1. 在FlutterBoost下如何管理Flutter页面的生命周期?原生的Flutter的AppLifecycleState事件会不一致,比如ViewAppear会导致app状态suspending或者paused。混合栈怎么处理?
回答:在混合栈下,页面事件基于以下自定义的事件:
```dart
enum ContainerLifeCycle {
Init,
Appear,
WillDisappear,
Disappear,
Destroy,
Background,
Foreground
}
```
对于页面事件重复,请参考下面的FAQ。
### 2. 如何判断flutter的widget或者container是当前可见的?
回答:有个api可以判断当前页面是否可见:
```dart
bool isTopContainer = FlutterBoost.BoostContainer.of(context).onstage
```
传入你widget的context,就能判断你的widget是否是可见的
基于这个API,可以判断你的widget是否可见,从而避免接收一些重复的生命周期消息。参考这个issue:https://github.com/alibaba/flutter_boost/issues/498
### 3. 您好,我想请教一下flutter_boost有关的问题:ABC三个都是flutter页面,从 A页面 -> B页面 -> C页面,当打开C页面时希望自动关掉B页面,当从C页面返回时直接返回A页面,可有什么方法?
回答:你只需要操作Native层的UINavigationController里的vc数组就可以了。就如同平时你操作普通的UIViewController一样。因为FlutterBoost对Native层的FlutterViewController和Dart层的flutter page的生命周期管理是一致的,当FlutterViewController被销毁,其在dart层管理的flutter page也会自动被销毁。
### 4. 在ios中voice over打开,demo在点击交互会crash;
回答:无障碍模式下目前Flutter Engine有bug,已经提交issue和PR给flutter啦。请参考这个issue:https://github.com/alibaba/flutter_boost/issues/488及其分析。提交给flutter的PR见这里:https://github.com/flutter/engine/pull/14155
### 5. 在ios模拟器下运行最新的flutter boost会闪退
回答:因为模拟器下flutter默认会将voice over模式打开,所以其实就是辅助模式,这回触发上面的bug:“在ios中voice over打开,demo在点击交互会crash”。
可参考Engine的代码注释:
```c++
#if TARGET_OS_SIMULATOR
// There doesn't appear to be any way to determine whether the accessibility
// inspector is enabled on the simulator. We conservatively always turn on the
// accessibility bridge in the simulator, but never assistive technology.
platformView->SetSemanticsEnabled(true);
platformView->SetAccessibilityFeatures(flags);
```
### 6. 似乎官方已经提供了混合栈的功能,参考这里:https://flutter.dev/docs/development/add-to-app; FlutterBoost是否有存在的必要?
回答:官方的解决方案仅仅是在native侧对FlutterViewController和Flutterengine进行解耦,如此可以一个FlutterEngine切换不同的FlutterViewController或者Activity进行渲染。但其并未解决Native和Flutter页面混合的问题,无法保证两侧的页面生命周期一致。即使是Flutter官方针对这个问题也是建议使用FlutterBoost。
其差别主要有:
|*|FlutterBoost1.5 |Flutter官方方案 |其他框架|
|----|----|----|----|
|是否支持混合页面之间随意跳转 |Y |N |Y|
|一致的页面生命周期管理(多Flutter页面) |Y |N |?|
|是否支持页面间数据传递(回传等) |Y |N |N|
|是否支持测滑手势 |Y |Y |Y|
|是否支持跨页的hero动画 |N |Y |N|
|内存等资源占用是否可控 |Y |Y |Y|
|是否提供一致的页面route方案 |Y |Y |N|
|iOS和Android能力及接口是否一致 |Y |N |N|
|框架是否稳定,支持Flutter1.9 |Y |N |?|
|是否已经支持到View级别混合 |N |N |N|
同时FlutterBoost也提供了一次性创建混合工程的命令:flutterboot。代码参考:https://github.com/alibaba-flutter/flutter-boot
### 如果我需要通过FlutterViewController再弹出一个新的但frame比较小的FlutterViewController,应该怎么实现?
回答:如果不加处理会遇到window大小变化的问题,但可以解决。具体可以参考这个issue:https://github.com/alibaba/flutter_boost/issues/435
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
# Release Note # Release Note
Please checkout the release note for the latest 0.1.61 to see changes [0.1.61 release note](https://github.com/alibaba/flutter_boost/releases) Please checkout the release note for the latest 0.1.64 to see changes [0.1.64 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost # 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 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). 
...@@ -27,16 +27,16 @@ You need to add Flutter to your project before moving on.The version of the flut ...@@ -27,16 +27,16 @@ You need to add Flutter to your project before moving on.The version of the flut
3. 0.1.60 is based on the flutter v1.9.1-hotfixes branch. Android does not support andriodx if other flutter branches will compile incorrectly 3. 0.1.60 is based on the flutter v1.9.1-hotfixes branch. Android does not support andriodx if other flutter branches will compile incorrectly
4. 0.1.61 is a bugfix for 0.1.60 4. 0.1.61--0.1.64 is a bugfix for 0.1.60
5. Statement of support for androidx 5. Statement of support for androidx
Current androidx branch is feature/flutter_1.9_androidx_upgrade Current androidx branch is v0.1.61-androidx-hotfixes
Is based on flutter v1.9.1-hotfixes branch, if other branches will compile incorrectly Is based on flutter v1.9.1-hotfixes branch, if other branches will compile incorrectly
Synchronize with the 0.1.60 code, and bugfix of 0.1.61 also merge to this branch. Synchronize with the 0.1.63 code, and bugfix also merge to this branch.
...@@ -52,14 +52,14 @@ support branch ...@@ -52,14 +52,14 @@ support branch
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.61' ref: '0.1.64'
``` ```
androidx 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: 'feature/flutter_1.9_androidx_upgrade' ref: 'v0.1.61-androidx-hotfixes'
``` ```
...@@ -68,7 +68,9 @@ flutter_boost: ...@@ -68,7 +68,9 @@ flutter_boost:
Please see the boost example for details. Please see the boost example for details.
# FAQ
please read this document:
<a href="Frequently Asked Question.md">FAQ</a>
# License # License
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
# Release Note # Release Note
请查看最新版本0.1.61的release note 确认变更,[0.1.61 release note](https://github.com/alibaba/flutter_boost/releases) 请查看最新版本0.1.64的release note 确认变更,[0.1.64 release note](https://github.com/alibaba/flutter_boost/releases)
# FlutterBoost # FlutterBoost
...@@ -16,6 +16,10 @@ ...@@ -16,6 +16,10 @@
在继续之前,您需要将Flutter集成到你现有的项目中。flutter sdk 的版本需要 v1.9.1-hotfixes,否则会编译失败. 在继续之前,您需要将Flutter集成到你现有的项目中。flutter sdk 的版本需要 v1.9.1-hotfixes,否则会编译失败.
# FAQ
请阅读这篇文章:
<a href="Frequently Asked Question.md">FAQ</a>
# boost 版本说明 # boost 版本说明
...@@ -26,16 +30,16 @@ ...@@ -26,16 +30,16 @@
3. 0.1.60 是基于flutter v1.9.1-hotfixes 分支,android如果其他flutter分支会编译错误,该版本不支持andriodx 3. 0.1.60 是基于flutter v1.9.1-hotfixes 分支,android如果其他flutter分支会编译错误,该版本不支持andriodx
4. 0.1.61 是对0.1.60 的bugfix 4. 0.1.61-- 0.1.64 是对0.1.60 的bugfix
5. 关于androidx 的支持声明 5. 关于androidx 的支持声明
目前androidx 分支为 feature/flutter_1.9_androidx_upgrade 目前androidx 分支为 v0.1.61-androidx-hotfixes
是基于flutter v1.9.1-hotfixes 分支,如果其他分支会编译错误 是基于flutter v1.9.1-hotfixes 分支,如果其他分支会编译错误
和0.1.60代码同步,同时0.1.61的 bugfix 也会合入该分支。 和0.1.60代码同步, bugfix 也会合入该分支。
...@@ -52,7 +56,7 @@ support分支 ...@@ -52,7 +56,7 @@ support分支
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.61' ref: '0.1.64'
``` ```
...@@ -61,7 +65,7 @@ androidx分支 ...@@ -61,7 +65,7 @@ androidx分支
flutter_boost: flutter_boost:
git: git:
url: 'https://github.com/alibaba/flutter_boost.git' url: 'https://github.com/alibaba/flutter_boost.git'
ref: 'feature/flutter_1.9_androidx_upgrade' ref: 'v0.1.61-androidx-hotfixes'
``` ```
......
...@@ -29,6 +29,7 @@ public class FlutterBoost { ...@@ -29,6 +29,7 @@ public class FlutterBoost {
static FlutterBoost sInstance = null; static FlutterBoost sInstance = null;
private long FlutterPostFrameCallTime = 0; private long FlutterPostFrameCallTime = 0;
private Application.ActivityLifecycleCallbacks mActivityLifecycleCallbacks;
public long getFlutterPostFrameCallTime() { public long getFlutterPostFrameCallTime() {
return FlutterPostFrameCallTime; return FlutterPostFrameCallTime;
...@@ -51,14 +52,20 @@ public class FlutterBoost { ...@@ -51,14 +52,20 @@ public class FlutterBoost {
mPlatform = platform; mPlatform = platform;
mManager = new FlutterViewContainerManager(); mManager = new FlutterViewContainerManager();
platform.getApplication().registerActivityLifecycleCallbacks(new Application.ActivityLifecycleCallbacks() { mActivityLifecycleCallbacks = new Application.ActivityLifecycleCallbacks() {
@Override @Override
public void onActivityCreated(Activity activity, Bundle savedInstanceState) { public void onActivityCreated(Activity activity, Bundle savedInstanceState) {
mCurrentActiveActivity = activity; mCurrentActiveActivity = activity;
if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) { if (mPlatform.whenEngineStart() == ConfigBuilder.ANY_ACTIVITY_CREATED) {
doInitialFlutter(); doInitialFlutter();
boostPluginRegistry();
} }
if (mPlatform.whenEngineStart() == ConfigBuilder.IMMEDIATELY) {
boostPluginRegistry();
}
} }
@Override @Override
...@@ -117,7 +124,9 @@ public class FlutterBoost { ...@@ -117,7 +124,9 @@ public class FlutterBoost {
mCurrentActiveActivity = null; mCurrentActiveActivity = null;
} }
} }
}); };
platform.getApplication().registerActivityLifecycleCallbacks(mActivityLifecycleCallbacks);
if (mPlatform.whenEngineStart() == ConfigBuilder.IMMEDIATELY) { if (mPlatform.whenEngineStart() == ConfigBuilder.IMMEDIATELY) {
...@@ -150,10 +159,16 @@ public class FlutterBoost { ...@@ -150,10 +159,16 @@ public class FlutterBoost {
flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint); flutterEngine.getDartExecutor().executeDartEntrypoint(entrypoint);
mRegistry = new BoostPluginRegistry(createEngine()); mRegistry = new BoostPluginRegistry(createEngine());
mPlatform.registerPlugins(mRegistry);
} }
public void boostPluginRegistry(){
if(mRegistry!=null&& !mRegistry.hasPlugin("boostPluginRegistry")){
mPlatform.registerPlugins(mRegistry);
mRegistry.registrarFor("boostPluginRegistry");
}
}
public static class ConfigBuilder { public static class ConfigBuilder {
...@@ -219,10 +234,7 @@ public class FlutterBoost { ...@@ -219,10 +234,7 @@ public class FlutterBoost {
return this; return this;
} }
public ConfigBuilder whenEngineDestory(int whenEngineDestory) {
this.whenEngineDestory = whenEngineDestory;
return this;
}
public ConfigBuilder lifecycleListener(BoostLifecycleListener lifecycleListener) { public ConfigBuilder lifecycleListener(BoostLifecycleListener lifecycleListener) {
this.lifecycleListener = lifecycleListener; this.lifecycleListener = lifecycleListener;
...@@ -259,10 +271,6 @@ public class FlutterBoost { ...@@ -259,10 +271,6 @@ public class FlutterBoost {
return ConfigBuilder.this.whenEngineStart; return ConfigBuilder.this.whenEngineStart;
} }
@Override
public int whenEngineDestroy() {
return ConfigBuilder.this.whenEngineDestory;
}
public FlutterView.RenderMode renderMode() { public FlutterView.RenderMode renderMode() {
return ConfigBuilder.this.renderMode; return ConfigBuilder.this.renderMode;
......
...@@ -82,11 +82,9 @@ public class FlutterViewContainerManager implements IContainerManager { ...@@ -82,11 +82,9 @@ public class FlutterViewContainerManager implements IContainerManager {
void removeRecord(IContainerRecord record) { void removeRecord(IContainerRecord record) {
mRecordStack.remove(record); mRecordStack.remove(record);
mRecordMap.remove(record.getContainer()); mRecordMap.remove(record.getContainer());
if(mRecordMap.isEmpty()){ // if(mRecordMap.isEmpty()){
if( FlutterBoost.instance().platform().whenEngineDestroy()== FlutterBoost.ConfigBuilder.All_FLUTTER_ACTIVITY_DESTROY){ //
FlutterBoost.instance().boostDestroy(); // }
}
}
} }
......
...@@ -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 int whenEngineDestroy();
public abstract FlutterView.RenderMode renderMode(); public abstract FlutterView.RenderMode renderMode();
...@@ -39,13 +38,6 @@ public abstract class Platform { ...@@ -39,13 +38,6 @@ public abstract class Platform {
public void registerPlugins(PluginRegistry mRegistry) { public void registerPlugins(PluginRegistry mRegistry) {
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(pluginsRegister!=null){ if(pluginsRegister!=null){
pluginsRegister.registerPlugins(mRegistry); pluginsRegister.registerPlugins(mRegistry);
......
...@@ -185,7 +185,8 @@ public class Utils { ...@@ -185,7 +185,8 @@ public class Utils {
} }
} }
}catch (Throwable t){ }catch (Throwable t){
Debuger.exception(t); // Debuger.exception(t);
t.printStackTrace();
} }
} }
......
...@@ -83,6 +83,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContainer ...@@ -83,6 +83,7 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContainer
ensureAlive(); ensureAlive();
if (FlutterBoost.instance().platform().whenEngineStart() == FlutterBoost.ConfigBuilder.FLUTTER_ACTIVITY_CREATED) { if (FlutterBoost.instance().platform().whenEngineStart() == FlutterBoost.ConfigBuilder.FLUTTER_ACTIVITY_CREATED) {
FlutterBoost.instance().doInitialFlutter(); FlutterBoost.instance().doInitialFlutter();
FlutterBoost.instance().boostPluginRegistry();
} }
// When "retain instance" is true, the FlutterEngine will survive configuration // When "retain instance" is true, the FlutterEngine will survive configuration
// changes. Therefore, we create a new one only if one does not already exist. // changes. Therefore, we create a new one only if one does not already exist.
...@@ -217,12 +218,16 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContainer ...@@ -217,12 +218,16 @@ public class FlutterActivityAndFragmentDelegate implements IFlutterViewContainer
ensureAlive(); ensureAlive();
BoostPluginRegistry registry = (BoostPluginRegistry) FlutterBoost.instance().getPluginRegistry(); BoostPluginRegistry registry = (BoostPluginRegistry) FlutterBoost.instance().getPluginRegistry();
if (registry != null) {
ActivityPluginBinding binding = registry.getRegistrarAggregate().getActivityPluginBinding(); ActivityPluginBinding binding = registry.getRegistrarAggregate().getActivityPluginBinding();
if (binding != null && (binding.getActivity() == this.host.getActivity())) { if (binding != null && (binding.getActivity() == this.host.getActivity())) {
registry.getRegistrarAggregate().onDetachedFromActivityForConfigChanges(); registry.getRegistrarAggregate().onDetachedFromActivityForConfigChanges();
flutterEngine.getActivityControlSurface().detachFromActivityForConfigChanges(); flutterEngine.getActivityControlSurface().detachFromActivityForConfigChanges();
} }
}
flutterView.release(); flutterView.release();
} }
......
...@@ -24,8 +24,26 @@ ...@@ -24,8 +24,26 @@
DF544AA72177253600931378 /* UIViewControllerDemo.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF544AA52177253600931378 /* UIViewControllerDemo.xib */; }; DF544AA72177253600931378 /* UIViewControllerDemo.xib in Resources */ = {isa = PBXBuildFile; fileRef = DF544AA52177253600931378 /* UIViewControllerDemo.xib */; };
DF544AD4217838EF00931378 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DF544AD3217838EF00931378 /* libc++.tbd */; }; DF544AD4217838EF00931378 /* libc++.tbd in Frameworks */ = {isa = PBXBuildFile; fileRef = DF544AD3217838EF00931378 /* libc++.tbd */; };
DFD80BFA217DF95400E3F036 /* PlatformRouterImp.m in Sources */ = {isa = PBXBuildFile; fileRef = DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */; }; DFD80BFA217DF95400E3F036 /* PlatformRouterImp.m in Sources */ = {isa = PBXBuildFile; fileRef = DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */; };
FA32AEF623B4A56E00449D68 /* NativeViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FA32AEF523B4A56D00449D68 /* NativeViewController.m */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
FA32AEEF23B4685B00449D68 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FA32AEEA23B4685A00449D68 /* products.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = EDB8DD4E9A4BE1510409988F;
remoteInfo = sources;
};
FA32AEF123B4686E00449D68 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = FA32AEEA23B4685A00449D68 /* products.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = 7EE23C83374079D8D3916ACE;
remoteInfo = All;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */ /* Begin PBXCopyFilesBuildPhase section */
9705A1C41CF9048500538489 /* Embed Frameworks */ = { 9705A1C41CF9048500538489 /* Embed Frameworks */ = {
isa = PBXCopyFilesBuildPhase; isa = PBXCopyFilesBuildPhase;
...@@ -68,6 +86,9 @@ ...@@ -68,6 +86,9 @@
DF544AD3217838EF00931378 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; }; DF544AD3217838EF00931378 /* libc++.tbd */ = {isa = PBXFileReference; lastKnownFileType = "sourcecode.text-based-dylib-definition"; name = "libc++.tbd"; path = "usr/lib/libc++.tbd"; sourceTree = SDKROOT; };
DFD80BF8217DF95400E3F036 /* PlatformRouterImp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformRouterImp.h; sourceTree = "<group>"; }; DFD80BF8217DF95400E3F036 /* PlatformRouterImp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PlatformRouterImp.h; sourceTree = "<group>"; };
DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformRouterImp.m; sourceTree = "<group>"; }; DFD80BF9217DF95400E3F036 /* PlatformRouterImp.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PlatformRouterImp.m; sourceTree = "<group>"; };
FA32AEEA23B4685A00449D68 /* products.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = products.xcodeproj; path = ../../../engine_github/src/out/ios_debug_unopt/products.xcodeproj; sourceTree = "<group>"; };
FA32AEF423B4A56D00449D68 /* NativeViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativeViewController.h; sourceTree = "<group>"; };
FA32AEF523B4A56D00449D68 /* NativeViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = NativeViewController.m; sourceTree = "<group>"; };
/* End PBXFileReference section */ /* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */ /* Begin PBXFrameworksBuildPhase section */
...@@ -120,6 +141,7 @@ ...@@ -120,6 +141,7 @@
97C146E51CF9000F007C117D = { 97C146E51CF9000F007C117D = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
FA32AEEA23B4685A00449D68 /* products.xcodeproj */,
9740EEB11CF90186004384FC /* Flutter */, 9740EEB11CF90186004384FC /* Flutter */,
97C146F01CF9000F007C117D /* Runner */, 97C146F01CF9000F007C117D /* Runner */,
97C146EF1CF9000F007C117D /* Products */, 97C146EF1CF9000F007C117D /* Products */,
...@@ -153,6 +175,8 @@ ...@@ -153,6 +175,8 @@
97C146F11CF9000F007C117D /* Supporting Files */, 97C146F11CF9000F007C117D /* Supporting Files */,
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */, 1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */,
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */, 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */,
FA32AEF423B4A56D00449D68 /* NativeViewController.h */,
FA32AEF523B4A56D00449D68 /* NativeViewController.m */,
); );
path = Runner; path = Runner;
sourceTree = "<group>"; sourceTree = "<group>";
...@@ -165,6 +189,14 @@ ...@@ -165,6 +189,14 @@
name = "Supporting Files"; name = "Supporting Files";
sourceTree = "<group>"; sourceTree = "<group>";
}; };
FA32AEEB23B4685A00449D68 /* Products */ = {
isa = PBXGroup;
children = (
FA32AEF023B4685B00449D68 /* sources */,
);
name = Products;
sourceTree = "<group>";
};
/* End PBXGroup section */ /* End PBXGroup section */
/* Begin PBXNativeTarget section */ /* Begin PBXNativeTarget section */
...@@ -180,11 +212,11 @@ ...@@ -180,11 +212,11 @@
9705A1C41CF9048500538489 /* Embed Frameworks */, 9705A1C41CF9048500538489 /* Embed Frameworks */,
3B06AD1E1E4923F5004D2608 /* Thin Binary */, 3B06AD1E1E4923F5004D2608 /* Thin Binary */,
3FC74F80EA9D039C70D1F681 /* [CP] Embed Pods Frameworks */, 3FC74F80EA9D039C70D1F681 /* [CP] Embed Pods Frameworks */,
D49B04E67D494964A3A713AC /* [CP] Copy Pods Resources */,
); );
buildRules = ( buildRules = (
); );
dependencies = ( dependencies = (
FA32AEF223B4686E00449D68 /* PBXTargetDependency */,
); );
name = Runner; name = Runner;
productName = Runner; productName = Runner;
...@@ -218,6 +250,12 @@ ...@@ -218,6 +250,12 @@
mainGroup = 97C146E51CF9000F007C117D; mainGroup = 97C146E51CF9000F007C117D;
productRefGroup = 97C146EF1CF9000F007C117D /* Products */; productRefGroup = 97C146EF1CF9000F007C117D /* Products */;
projectDirPath = ""; projectDirPath = "";
projectReferences = (
{
ProductGroup = FA32AEEB23B4685A00449D68 /* Products */;
ProjectRef = FA32AEEA23B4685A00449D68 /* products.xcodeproj */;
},
);
projectRoot = ""; projectRoot = "";
targets = ( targets = (
97C146ED1CF9000F007C117D /* Runner */, 97C146ED1CF9000F007C117D /* Runner */,
...@@ -225,6 +263,16 @@ ...@@ -225,6 +263,16 @@
}; };
/* End PBXProject section */ /* End PBXProject section */
/* Begin PBXReferenceProxy section */
FA32AEF023B4685B00449D68 /* sources */ = {
isa = PBXReferenceProxy;
fileType = "compiled.mach-o.executable";
path = sources;
remoteRef = FA32AEEF23B4685B00449D68 /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */ /* Begin PBXResourcesBuildPhase section */
97C146EC1CF9000F007C117D /* Resources */ = { 97C146EC1CF9000F007C117D /* Resources */ = {
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
...@@ -262,8 +310,8 @@ ...@@ -262,8 +310,8 @@
files = ( files = (
); );
inputPaths = ( inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh", "${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh",
"${PODS_ROOT}/../.symlinks/flutter/ios/Flutter.framework", "${PODS_ROOT}/../.symlinks/flutter/ios_debug_sim_unopt/Flutter.framework",
); );
name = "[CP] Embed Pods Frameworks"; name = "[CP] Embed Pods Frameworks";
outputPaths = ( outputPaths = (
...@@ -271,7 +319,7 @@ ...@@ -271,7 +319,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n"; shellScript = "\"${PODS_ROOT}/Target Support Files/Pods-Runner/Pods-Runner-frameworks.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
9740EEB61CF901F6004384FC /* Run Script */ = { 9740EEB61CF901F6004384FC /* Run Script */ = {
...@@ -303,22 +351,7 @@ ...@@ -303,22 +351,7 @@
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh; shellPath = /bin/sh;
shellScript = "diff \"${PODS_ROOT}/../Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n"; shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
D49B04E67D494964A3A713AC /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Runner/Pods-Runner-resources.sh\"\n";
showEnvVarsInLog = 0; showEnvVarsInLog = 0;
}; };
/* End PBXShellScriptBuildPhase section */ /* End PBXShellScriptBuildPhase section */
...@@ -333,11 +366,20 @@ ...@@ -333,11 +366,20 @@
97C146F31CF9000F007C117D /* main.m in Sources */, 97C146F31CF9000F007C117D /* main.m in Sources */,
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */, 1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */,
DF544AA62177253600931378 /* UIViewControllerDemo.m in Sources */, DF544AA62177253600931378 /* UIViewControllerDemo.m in Sources */,
FA32AEF623B4A56E00449D68 /* NativeViewController.m in Sources */,
); );
runOnlyForDeploymentPostprocessing = 0; runOnlyForDeploymentPostprocessing = 0;
}; };
/* End PBXSourcesBuildPhase section */ /* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
FA32AEF223B4686E00449D68 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = All;
targetProxy = FA32AEF123B4686E00449D68 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */ /* Begin PBXVariantGroup section */
97C146FA1CF9000F007C117D /* Main.storyboard */ = { 97C146FA1CF9000F007C117D /* Main.storyboard */ = {
isa = PBXVariantGroup; isa = PBXVariantGroup;
......
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
#import <UIKit/UIKit.h> #import <UIKit/UIKit.h>
#import <flutter_boost/FlutterBoost.h> #import <flutter_boost/FlutterBoost.h>
@interface AppDelegate : FLBFlutterAppDelegate <UIApplicationDelegate> @interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nullable, nonatomic, strong) UIWindow *window;
@end @end
...@@ -9,6 +9,7 @@ ...@@ -9,6 +9,7 @@
#import "AppDelegate.h" #import "AppDelegate.h"
#import "UIViewControllerDemo.h" #import "UIViewControllerDemo.h"
#import "PlatformRouterImp.h" #import "PlatformRouterImp.h"
#import "NativeViewController.h"
#import <flutter_boost/FlutterBoost.h> #import <flutter_boost/FlutterBoost.h>
@interface AppDelegate () @interface AppDelegate ()
...@@ -50,19 +51,19 @@ ...@@ -50,19 +51,19 @@
self.window.rootViewController = rvc; self.window.rootViewController = rvc;
UIButton *nativeButton = [UIButton buttonWithType:UIButtonTypeCustom]; UIButton *nativeButton = [UIButton buttonWithType:UIButtonTypeCustom];
nativeButton.frame = CGRectMake(self.window.frame.size.width * 0.5 - 50, 200, 100, 45); nativeButton.frame = CGRectMake(self.window.frame.size.width * 0.5 - 50, 200, 100, 40);
nativeButton.backgroundColor = [UIColor redColor]; nativeButton.backgroundColor = [UIColor redColor];
[nativeButton setTitle:@"push native" forState:UIControlStateNormal]; [nativeButton setTitle:@"push native" forState:UIControlStateNormal];
[nativeButton addTarget:self action:@selector(pushNative) forControlEvents:UIControlEventTouchUpInside]; [nativeButton addTarget:self action:@selector(pushNative) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:nativeButton]; [self.window addSubview:nativeButton];
UIButton *pushEmbeded = [UIButton buttonWithType:UIButtonTypeCustom];
pushEmbeded.frame = CGRectMake(self.window.frame.size.width * 0.5 - 70, 150, 140, 40);
pushEmbeded.backgroundColor = [UIColor redColor];
[pushEmbeded setTitle:@"push embeded" forState:UIControlStateNormal];
[pushEmbeded addTarget:self action:@selector(pushEmbeded) forControlEvents:UIControlEventTouchUpInside];
[self.window addSubview:pushEmbeded];
return YES; return YES;
} }
...@@ -74,6 +75,12 @@ ...@@ -74,6 +75,12 @@
[nvc pushViewController:vc animated:YES]; [nvc pushViewController:vc animated:YES];
} }
- (void)pushEmbeded
{
UINavigationController *nvc = (id)self.window.rootViewController;
UIViewController *vc = [[NativeViewController alloc] init];
[nvc pushViewController:vc animated:YES];
}
- (void)applicationWillResignActive:(UIApplication *)application { - (void)applicationWillResignActive:(UIApplication *)application {
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
......
//
// NativeViewController.h
// Runner
//
// Created by yujie on 2019/12/26.
// Copyright © 2019 The Chromium Authors. All rights reserved.
//
#import <UIKit/UIKit.h>
NS_ASSUME_NONNULL_BEGIN
@interface NativeViewController : UIViewController
@end
NS_ASSUME_NONNULL_END
//
// NativeViewController.m
// Runner
//
// Created by yujie on 2019/12/26.
// Copyright © 2019 The Chromium Authors. All rights reserved.
//
#import "NativeViewController.h"
#import <Flutter/Flutter.h>
#import <flutter_boost/FlutterBoost.h>
@interface NativeViewController ()
@property(nonatomic, strong)FLBFlutterViewContainer *flutterContainer;
@end
@implementation NativeViewController
- (instancetype)init{
if (self = [super init]) {
_flutterContainer = [[FLBFlutterViewContainer alloc]init];
[_flutterContainer setName:@"embeded" params:@{}];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.view.backgroundColor = [UIColor grayColor];
self.flutterContainer.view.frame = CGRectInset(self.view.bounds, 30, 100);
[self.view addSubview:self.flutterContainer.view];
[self addChildViewController:self.flutterContainer];
UIButton *nativeButton = [UIButton buttonWithType:UIButtonTypeCustom];
nativeButton.frame = CGRectMake(50,self.view.bounds.size.height-50,200,40);
nativeButton.backgroundColor = [UIColor blueColor];
[nativeButton setTitle:@"Button in Native" forState:UIControlStateNormal];
[nativeButton addTarget:self action:@selector(pushMe) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:nativeButton];
}
- (void)pushMe
{
UIViewController *vc = [[UIViewController alloc] init];
[self.navigationController pushViewController:vc animated:YES];
}
- (void)viewDidAppear:(BOOL)animated{
[super viewDidAppear:animated];
//注意这行代码不可缺少
// [self.flutterContainer.view setNeedsLayout];
// [self.flutterContainer.view layoutIfNeeded];
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
@end
...@@ -17,6 +17,7 @@ class _MyAppState extends State<MyApp> { ...@@ -17,6 +17,7 @@ class _MyAppState extends State<MyApp> {
super.initState(); super.initState();
FlutterBoost.singleton.registerPageBuilders({ FlutterBoost.singleton.registerPageBuilders({
'embeded': (pageName, params, _)=>EmbededFirstRouteWidget(),
'first': (pageName, params, _) => FirstRouteWidget(), 'first': (pageName, params, _) => FirstRouteWidget(),
'second': (pageName, params, _) => SecondRouteWidget(), 'second': (pageName, params, _) => SecondRouteWidget(),
'tab': (pageName, params, _) => TabRouteWidget(), 'tab': (pageName, params, _) => TabRouteWidget(),
......
...@@ -26,6 +26,26 @@ class FirstRouteWidget extends StatelessWidget { ...@@ -26,6 +26,26 @@ class FirstRouteWidget extends StatelessWidget {
} }
} }
class EmbededFirstRouteWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: RaisedButton(
child: Text('Open second route'),
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 { class SecondRouteWidget extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
......
...@@ -35,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -35,6 +35,7 @@ NS_ASSUME_NONNULL_BEGIN
- (id<FLBFlutterProvider>)flutterProvider; - (id<FLBFlutterProvider>)flutterProvider;
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform - (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
withEngine:(FlutterEngine* _Nullable)engine
onStart:(void (^)(FlutterEngine *engine))callback; onStart:(void (^)(FlutterEngine *engine))callback;
- (FlutterViewController *)flutterViewController; - (FlutterViewController *)flutterViewController;
...@@ -44,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -44,6 +45,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)addUniqueViewController:(id<FLBFlutterContainer>)vc; - (void)addUniqueViewController:(id<FLBFlutterContainer>)vc;
- (void)removeViewController:(id<FLBFlutterContainer>)vc; - (void)removeViewController:(id<FLBFlutterContainer>)vc;
- (BOOL)isTop:(NSString *)pageId; - (BOOL)isTop:(NSString *)pageId;
- (NSInteger)pageCount;
#pragma mark - App Control #pragma mark - App Control
- (void)pause; - (void)pause;
......
...@@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -32,6 +32,7 @@ NS_ASSUME_NONNULL_BEGIN
- (void)addUnique:(id<FLBFlutterContainer>)vc; - (void)addUnique:(id<FLBFlutterContainer>)vc;
- (void)remove:(id<FLBFlutterContainer>)vc; - (void)remove:(id<FLBFlutterContainer>)vc;
- (BOOL)contains:(id<FLBFlutterContainer>)vc; - (BOOL)contains:(id<FLBFlutterContainer>)vc;
- (NSInteger)pageCount;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -79,6 +79,10 @@ ...@@ -79,6 +79,10 @@
return _idStk.lastObject; return _idStk.lastObject;
} }
- (NSInteger)pageCount{
return _idStk.count;
}
#if DEBUG #if DEBUG
- (void)dump:(NSString*)flag{ - (void)dump:(NSString*)flag{
NSMutableString *log = [[NSMutableString alloc]initWithFormat:@"[DEBUG]--%@--PageStack uid/name", flag]; NSMutableString *log = [[NSMutableString alloc]initWithFormat:@"[DEBUG]--%@--PageStack uid/name", flag];
......
...@@ -26,10 +26,17 @@ ...@@ -26,10 +26,17 @@
#import "FLBPlatform.h" #import "FLBPlatform.h"
#import "FLBTypes.h" #import "FLBTypes.h"
NS_ASSUME_NONNULL_BEGIN
@interface FlutterBoostPlugin : NSObject<FlutterPlugin> @interface FlutterBoostPlugin : NSObject<FlutterPlugin>
#pragma mark - Initializer #pragma mark - Initializer
+ (instancetype)sharedInstance; + (instancetype)sharedInstance;
/**
* 获取当前管理的页面栈中页面的个数
*
*/
+ (NSInteger)pageCount;
/** /**
* 初始化FlutterBoost混合栈环境。应在程序使用混合栈之前调用。如在AppDelegate中 * 初始化FlutterBoost混合栈环境。应在程序使用混合栈之前调用。如在AppDelegate中
* *
...@@ -38,6 +45,16 @@ ...@@ -38,6 +45,16 @@
*/ */
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform - (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(FlutterEngine *engine))callback; onStart:(void (^)(FlutterEngine *engine))callback;
/**
* 初始化FlutterBoost混合栈环境。应在程序使用混合栈之前调用。如在AppDelegate中
*
* @param platform 平台层实现FLBPlatform的对象
* @param engine 外部实例化engine后传入
* @param callback 启动之后回调
*/
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
engine:(FlutterEngine* _Nullable)engine
onStart:(void (^)(FlutterEngine *engine))callback;
#pragma mark - Some properties. #pragma mark - Some properties.
- (BOOL)isRunning; - (BOOL)isRunning;
...@@ -108,4 +125,12 @@ ...@@ -108,4 +125,12 @@
exts:(NSDictionary *)exts exts:(NSDictionary *)exts
onPageFinished:(void (^)(NSDictionary *))resultCallback onPageFinished:(void (^)(NSDictionary *))resultCallback
completion:(void (^)(BOOL))completion; completion:(void (^)(BOOL))completion;
//切记:在destroyPluginContext前务必将所有FlutterViewController及其子类的实例销毁。在这里是FLBFlutterViewContainer。否则会异常;以下是全部步骤
//1. 首先通过为所有FlutterPlugin的methodChannel属性设为nil来解除其与FlutterEngine的间接强引用
//2. 销毁所有的FlutterViewController实例(或保证所有FlutterVC已经退出),来解除其与FlutterEngine的强引用,在每个VC卸载的时候FlutterEngine会调用destroyContext
//3. 调用FlutterBoostPlugin.destroyPluginContext函数来解除与其内部context的强引用。内部持有的FlutterEngine也会被卸载(非外部传入的情形)
//4. 如果是外部传入的FlutterEngine,需要外部自己释放
- (void)destroyPluginContext;
@end @end
NS_ASSUME_NONNULL_END
...@@ -111,16 +111,29 @@ ...@@ -111,16 +111,29 @@
return _instance; return _instance;
} }
+ (NSInteger)pageCount{
id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application];
return [app pageCount];
}
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
onStart:(void (^)(FlutterEngine *engine))callback;
{
[self startFlutterWithPlatform:platform engine:nil onStart:callback];
}
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform - (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
engine:(FlutterEngine* _Nullable)engine
onStart:(void (^)(FlutterEngine *engine))callback; onStart:(void (^)(FlutterEngine *engine))callback;
{ {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
__weak __typeof__(self) weakSelf = self; __weak __typeof__(self) weakSelf = self;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
__strong __typeof__(weakSelf) self = weakSelf; __strong __typeof__(weakSelf) self = weakSelf;
self.factory = FLBFactory.new; FLBFactory *factory = FLBFactory.new;
self.application = [self->_factory createApplication:platform]; self.application = [factory createApplication:platform];
[self.application startFlutterWithPlatform:platform [self.application startFlutterWithPlatform:platform
withEngine:engine
onStart:callback]; onStart:callback];
}); });
} }
...@@ -169,4 +182,9 @@ ...@@ -169,4 +182,9 @@
id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application]; id<FLBFlutterApplicationInterface> app = [[FlutterBoostPlugin sharedInstance] application];
[app close:uniqueId result:resultData exts:exts completion:completion]; [app close:uniqueId result:resultData exts:exts completion:completion];
} }
- (void)destroyPluginContext{
self.methodChannel = nil;
self.application = nil;
}
@end @end
...@@ -28,7 +28,6 @@ ...@@ -28,7 +28,6 @@
#import "FlutterBoostPlugin.h" #import "FlutterBoostPlugin.h"
@interface FlutterBoostPlugin() @interface FlutterBoostPlugin()
@property (nonatomic,strong) id<FLBFlutterApplicationInterface> application; @property (nonatomic,strong) id<FLBFlutterApplicationInterface> application;
@property (nonatomic,strong) id<FLBAbstractFactory> factory;
@property (nonatomic,strong) FlutterMethodChannel *methodChannel; @property (nonatomic,strong) FlutterMethodChannel *methodChannel;
@property (nonatomic,copy) NSString *fPageId; @property (nonatomic,copy) NSString *fPageId;
@property (nonatomic,copy) NSString *fPagename; @property (nonatomic,copy) NSString *fPagename;
......
...@@ -50,12 +50,13 @@ ...@@ -50,12 +50,13 @@
} }
- (void)startFlutterWithPlatform:(id<FLBPlatform>)platform - (void)startFlutterWithPlatform:(id<FLBPlatform>)platform
withEngine:(FlutterEngine* _Nullable)engine
onStart:(void (^)(FlutterEngine *engine))callback onStart:(void (^)(FlutterEngine *engine))callback
{ {
static dispatch_once_t onceToken; static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{ dispatch_once(&onceToken, ^{
self.platform = platform; self.platform = platform;
self.viewProvider = [[FLBFlutterEngine alloc] initWithPlatform:platform]; self.viewProvider = [[FLBFlutterEngine alloc] initWithPlatform:platform engine:engine];
self.isRunning = YES; self.isRunning = YES;
if(callback) callback(self.viewProvider.engine); if(callback) callback(self.viewProvider.engine);
}); });
...@@ -115,6 +116,9 @@ ...@@ -115,6 +116,9 @@
return [_manager remove:vc]; return [_manager remove:vc];
} }
- (NSInteger)pageCount{
return [_manager pageCount];
}
- (BOOL)isTop:(NSString *)pageId - (BOOL)isTop:(NSString *)pageId
{ {
......
...@@ -28,6 +28,6 @@ ...@@ -28,6 +28,6 @@
NS_ASSUME_NONNULL_BEGIN NS_ASSUME_NONNULL_BEGIN
@interface FLBFlutterEngine : NSObject<FLBFlutterProvider> @interface FLBFlutterEngine : NSObject<FLBFlutterProvider>
- (instancetype)initWithPlatform:(id<FLBPlatform>_Nullable)platform; - (instancetype)initWithPlatform:(id<FLBPlatform> _Nullable)platform engine:(FlutterEngine* _Nullable)engine;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -35,13 +35,17 @@ ...@@ -35,13 +35,17 @@
@implementation FLBFlutterEngine @implementation FLBFlutterEngine
- (instancetype)initWithPlatform:(id<FLBPlatform> _Nullable)platform - (instancetype)initWithPlatform:(id<FLBPlatform> _Nullable)platform engine:(FlutterEngine * _Nullable)engine
{ {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks" #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
if (self = [super init]) { if (self = [super init]) {
if(!engine){
_engine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil]; _engine = [[FlutterEngine alloc] initWithName:@"io.flutter" project:nil];
}else{
_engine = engine;
}
if(platform && if(platform &&
[platform respondsToSelector: @selector(entryForDart)] && [platform respondsToSelector: @selector(entryForDart)] &&
platform.entryForDart){ platform.entryForDart){
...@@ -69,7 +73,7 @@ ...@@ -69,7 +73,7 @@
- (instancetype)init - (instancetype)init
{ {
return [self initWithPlatform:nil]; return [self initWithPlatform:nil engine:nil];
} }
- (void)pause - (void)pause
...@@ -91,19 +95,14 @@ ...@@ -91,19 +95,14 @@
- (void)didEnterBackground - (void)didEnterBackground
{ {
[BoostMessageChannel sendEvent:@"background" [BoostMessageChannel sendEvent:@"lifecycle"
arguments:nil]; arguments:@{@"type":@"background"}];
} }
- (void)willEnterForeground - (void)willEnterForeground
{ {
[BoostMessageChannel sendEvent:@"foreground" [BoostMessageChannel sendEvent:@"lifecycle"
arguments:nil]; arguments:@{@"type":@"foreground"}];
}
- (FlutterEngine *)engine
{
return _engine;
} }
- (void)atacheToViewController:(FlutterViewController *)vc - (void)atacheToViewController:(FlutterViewController *)vc
...@@ -128,5 +127,8 @@ ...@@ -128,5 +127,8 @@
// [self detach]; // [self detach];
} }
- (void)dealloc{
[self.engine setViewController:nil];
}
@end @end
...@@ -31,6 +31,5 @@ NS_ASSUME_NONNULL_BEGIN ...@@ -31,6 +31,5 @@ NS_ASSUME_NONNULL_BEGIN
@property (nonatomic,copy,readwrite) NSString *name; @property (nonatomic,copy,readwrite) NSString *name;
- (instancetype)init NS_DESIGNATED_INITIALIZER; - (instancetype)init NS_DESIGNATED_INITIALIZER;
- (void)surfaceUpdated:(BOOL)appeared; - (void)surfaceUpdated:(BOOL)appeared;
- (void)setEnableForRunnersBatch:(BOOL)enable;
@end @end
NS_ASSUME_NONNULL_END NS_ASSUME_NONNULL_END
...@@ -158,11 +158,6 @@ static NSUInteger kInstanceCounter = 0; ...@@ -158,11 +158,6 @@ static NSUInteger kInstanceCounter = 0;
[FLUTTER_APP.flutterProvider detach]; [FLUTTER_APP.flutterProvider detach];
} }
- (void)setEnableForRunnersBatch:(BOOL)enable{
//dummy function
NSLog(@"[DEBUG]- I did nothing, I am innocent");
}
#pragma mark - Life circle methods #pragma mark - Life circle methods
- (void)viewDidLayoutSubviews - (void)viewDidLayoutSubviews
...@@ -188,6 +183,7 @@ static NSUInteger kInstanceCounter = 0; ...@@ -188,6 +183,7 @@ static NSUInteger kInstanceCounter = 0;
} }
[super viewWillAppear:animated]; [super viewWillAppear:animated];
[self.view setNeedsLayout];
//instead of calling [super viewWillAppear:animated];, call super's super //instead of calling [super viewWillAppear: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]),
......
...@@ -206,6 +206,18 @@ class ContainerCoordinator { ...@@ -206,6 +206,18 @@ class ContainerCoordinator {
?.pushContainer(_createContainerSettings(name, params, pageId)); ?.pushContainer(_createContainerSettings(name, params, pageId));
} }
//TODO, 需要验证android代码是否也可以移到这里
if (Platform.isIOS) {
try {
final SemanticsOwner owner =
WidgetsBinding.instance.pipelineOwner?.semanticsOwner;
final SemanticsNode root = owner?.rootSemanticsNode;
root?.detach();
root?.attach(owner);
} catch (e) {
assert(false, e.toString());
}
}
return true; return true;
} }
...@@ -254,9 +266,14 @@ class ContainerCoordinator { ...@@ -254,9 +266,14 @@ class ContainerCoordinator {
} }
bool _nativeContainerWillDealloc(String name, Map params, String pageId) { bool _nativeContainerWillDealloc(String name, Map params, String pageId) {
try{
performContainerLifeCycle(_createContainerSettings(name, params, pageId), performContainerLifeCycle(_createContainerSettings(name, params, pageId),
ContainerLifeCycle.Destroy); ContainerLifeCycle.Destroy);
} catch (e){
Logger.log(
'nativeContainerWillDealloc error: ${e}' );
}
FlutterBoost.containerManager?.remove(pageId); FlutterBoost.containerManager?.remove(pageId);
Logger.log( Logger.log(
......
...@@ -83,6 +83,8 @@ class ContainerManagerState extends State<BoostContainerManager> { ...@@ -83,6 +83,8 @@ class ContainerManagerState extends State<BoostContainerManager> {
//Number of containers. //Number of containers.
int get containerCounts => _offstage.length; int get containerCounts => _offstage.length;
List<BoostContainer> get offstage => _offstage;
//Setting for current visible container. //Setting for current visible container.
BoostContainerSettings get onstageSettings => _onstage.settings; BoostContainerSettings get onstageSettings => _onstage.settings;
......
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.61 version: 0.1.64
author: Alibaba Xianyu author: Alibaba Xianyu
homepage: https://github.com/alibaba/flutter_boost homepage: https://github.com/alibaba/flutter_boost
......
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