This article belongs to the <Jane books - Liu strong> original, reproduced please specify:
<Jane books - Liu Zhuang> https://www.jianshu.com/p/d27c1f5ee3ff
iOS access Flutter
During iOS
and Flutter
when mixed, iOS
than Android
access slightly complicated, but also good. There are now a lot of access to Flutter
programs, but most are stereotyped copy of each other, no meaning.
Conducted Flutter
before mixed, there are some necessary documents.
xcode_backend.sh
Files, configurationflutter
time environment byFlutter
providing toolkits.xcconfig
Environment variable file,Flutter
automatically generated project, each project is different.
xcconfig file
xcconfig
It is the Xcode
configuration file, Flutter
in which some basic configuration information and the path, access Flutter
pre-need to first xcconfig
access in, otherwise some paths and other information will be wrong or missing.
Flutter
The xcconfig
consists of three files, Debug.xcconfig
, , Release.xcconfig
, Generated.xcconfig
these files need to be disposed at a position below and according to the different configuration files of different environments.
Project -> Info -> Development Target -> Configurations
复制代码
Some large projects have been Configurations
set up in xcconfig
the file, since each Target
kind of environment can have only one xcconfig
file, it can be an existing xcconfig
file import
introduced Generated.xcconfig
files, and no need to distinguish the environment.
Script file
xcode_backend.sh
Script files used to build and export the Flutter
product, which is the Flutter
development kit provided to us by default. In the works require Target
the Build Phases
addition of a Run Script
file and paste the following script code. It should be noted, do not forget the previous /bin/sh
operation, otherwise it will cause permission errors.
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" build
/bin/sh "$FLUTTER_ROOT/packages/flutter_tools/bin/xcode_backend.sh" embed
复制代码
In the xcode_backend.sh
three types of parameters, build
, thin
, embed
, thin
does not mean much, the other two are responsible for building and exporting.
Mixed-use development
You can then Xcode
compile the project, this time will certainly incorrect report. But do not panic, after an error in the project we will find a home directory named Flutter
file folder, which will contain two framework
, this folder is Flutter
compiled product, we will be dragged into the overall project to this folder.
This time we can iOS
add project Flutter
codes, the following is the detailed steps.
- The
AppDelegate
integration of changeFlutterAppDelegate
, and the need to follow theFlutterAppLifeCycleProvider
agency.
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>
@interface AppDelegate : FlutterAppDelegate <FlutterAppLifeCycleProvider>
@end
复制代码
- Create an
FlutterPluginAppLifeCycleDelegate
instance of an object, the object is responsible for managingFlutter
the life cycle, and fromPlatform
the receiving sideAppDelegate
of the event. I will declare it as a direct property, inAppDelegate
the various methods, call its methods of transit operations.
- (BOOL)application:(UIApplication *)application willFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[self.lifeCycleDelegate application:application willFinishLaunchingWithOptions:launchOptions];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
[self.lifeCycleDelegate applicationWillResignActive:application];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
[self.lifeCycleDelegate application:application openURL:url sourceApplication:sourceApplication annotation:annotation];
return YES;
}
复制代码
- You can then join
Flutter
the way the code is added is also very simple, straightforward example of aFlutterViewController
controller can be, do not need to pass additional parameters into account (here is not considered multi-instance issues).
FlutterViewController *flutterViewController = [[FlutterViewController alloc] init];
复制代码
Flutter
Think of it as a canvas, then instantiate a canvas up, in fact, nothing is done in the current page.
Common Errors
This step is to integrate the operation has been completed, but many people will encounter some errors in the integration process, here are some common mistakes.
- Wrong path, not read
xcode_backend.sh
documents. This is because the environment variable isFLUTTER_ROOT
not acquired,FLUTTER_ROOT
configurationGenerated.xcconfig
, you can look at the document in question is not configured. lipo info *** arm64
An error like this, usually because thexcode_backend.sh
script causes, you can check theFLUTTER_ROOT
environment variable is correct.- This problem usually because of the following rights cause, you can view
Build Phases
the script writing is not a problem.
***/flutter_tools/bin/xcode_backend.sh: Permission denied
复制代码
Mixed-use development
In carrying mixed, Flutter
there is a great advantage is that if the Flutter
code is wrong, will not lead to the collapse of native applications. When Flutter
the time code appears crashes, error message is displayed on the screen.
During the development process often involves a network request and persistence of the problem, if mixed, then it may be related to write two sets of logic. For example there are some public network request parameters, or return to a unified data processing, etc., if the logic of maintaining two words will be easy to go wrong. It is recommended that the network request and persistence operations are handed over to Platform
treatment, Flutter
the side is only responsible to Platform
request and brought to use.
This process involves the issue of data interaction ends, Flutter
for mixed given two options, MethodChannel
and EventChannel
. From the name of view, it is a method call, the other is the event delivery. However, the actual development process, only need to use MethodChannel
to complete all requirements.
Flutter to Native
The following is a Flutter
call Native
code, in Native
through the FlutterMethodChannel
setting specified callback code, and the process parameters and receiving. By the Flutter
by MethodChannel
to Native
initiate calls, and pass the corresponding parameters.
In the code Flutter
to build the data model good side, then call MethodChannel
the invokeMethod
triggered Native
callbacks. Native
Get Flutter
pass over the data, parse and execute playback operation, playback status code will then callback to Flutter
side, interaction is complete.
import 'package:flutter/services.dart';
Future<Null> playVideo() async{
var methodChannel = MethodChannel('flutterChannelName');
Map params = {'playID' : '302998298', 'duration' : '2520', 'name' : '三生三世十里桃花'};
String result;
result = await methodChannel.invokeMethod('PlayAlbumVideo', params);
String playID = params['playID'];
String duration = params['duration'];
String name = params['name'];
showCupertinoDialog(context: context, builder: (BuildContext context){
return CupertinoAlertDialog(
title: Text(result),
content: Text('name:$name playID:$playID duration:$duration'),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: (){
Navigator.pop(context);
},
)
],
);
});
}
复制代码
NSString *channelName = @"flutterChannelName";
FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:flutterVC];
[methodChannel setMethodCallHandler:^(FlutterMethodCall * _Nonnull call, FlutterResult _Nonnull result) {
if ([call.method isEqualToString:@"PlayAlbumVideo"]) {
NSDictionary *params = call.arguments;
VideoPlayerModel *model = [[VideoPlayerModel alloc] init];
model.playID = [params stringForKey:@"playID"];
model.duration = [params stringForKey:@"duration"];
model.name = [params stringForKey:@"name"];
NSString *playStatus = [SVHistoryPlayUtil playVideoWithModel:model
showPlayerVC:self.flutterVC];
result([NSString stringWithFormat:@"播放状态 %@", playStatus]);
}
}];
复制代码
Native to Flutter
Native
Calling Flutter
code and Flutter
calls Native
substantially similar, just call and set up different roles callback. Also, Flutter
due to receive Native
the callback messages, you need to register a callback, the Native
launch of the Flutter
call and pass parameters.
Native
And Flutter
the need to set up a call each other names, each name corresponds to a MethodChannel
target, each object can initiate multiple calls to different call to invokeMethod
make distinction.
import 'package:flutter/services.dart';
@override
void initState() {
super.initState();
MethodChannel methodChannel = MethodChannel('nativeChannelName');
methodChannel.setMethodCallHandler(callbackHandler);
}
Future<dynamic> callbackHandler(MethodCall call) {
if(call.method == 'requestHomeData') {
String title = call.arguments['title'];
String content = call.arguments['content'];
showCupertinoDialog(context: context, builder: (BuildContext context){
return CupertinoAlertDialog(
title: Text(title),
content: Text(content),
actions: <Widget>[
FlatButton(
child: Text('确定'),
onPressed: (){
Navigator.pop(context);
},
)
],
);
});
}
}
复制代码
NSString *channelName = @"nativeChannelName";
FlutterMethodChannel *methodChannel = [FlutterMethodChannel methodChannelWithName:channelName binaryMessenger:flutterVC];
[RequestManager requestWithURL:url success:^(NSDictionary *result) {
[methodChannel invokeMethod:@"requestHomeData" arguments:result];
}];
复制代码
Debugging tools
In iOS
and Android
development in their respective compilers provide a good set of debugging tools, facilitate memory, performance, and other debug view. Flutter
Also provides debugging tools and commands, based on the following VSCode
compiler is concerned about Flutter
debugging, relatively speaking Android Studio
debugging features provided may be some more.
Performance Tuning
VSCode
It supports some simple command-line debugger commands, the program is running in Command Palette
the command line input panel performance
, and select the Toggle Performance Overlay
command. This command has a requirement is needed in the App running.
Then there will be a performance on the panel interface, this page is divided into two parts, frame rate, GPU threads and the UI thread. Each part is divided into three horizontal lines, representing different levels of Caton. If it is green then it would not affect the interface rendering, red if it is likely to affect the smoothness of the interface. If the red line appears, the code is currently executing needs to be optimized.
Dart DevTools
VSCode
To Flutter
provide a set of debugging tools - Dart DevTools
, this tool set is very wide, includes performance, UI, hot update, thermal overload, log logs and many other functions.
Installation Dart DevTools
later, in the App running state, in VSCode
the lower right corner to start this tool, the tool will show the form of a web page, and can control App.
Main interface
Here is Dart DevTools
the main interface, I am running a micro-channel interface similar to the App. From Inspector
can see the view of the structure of the page, Android Studio
it has a similar function. The whole page is a tree structure, and select one of the controls, will demonstrate the value of the variable on the right side of the control, for example frame
, color
and so on, this feature is very useful.
I am running device Xcode
simulator, if you want to switch Android
in Material Design
, click on the iOS
button to directly change the device. When it comes to just above view memory performance panel, click on the iOS
button next Performance Overlay
to appear.
Select Widget
If you want to know the Dart DevTools
node selected, which corresponds to a specific control, you can select Select Widget Mode
the control highlight on the screen is selected.
Debug Paint
Click Debug Paint
allows each control are highlighted by this mode you can see ListView
the distance between the sliding direction, and the size and control of each control.
In addition, you can also select Paint Baseline
the highlighted bottom line of all controls, functions and Debug Paint
similar, not narrative.
Memory
Dart DevTools
Memory debugging tools provide more intuitive, it can display memory usage in real time. In the beginning of operation, we found a peak memory, put the mouse up can see the specific memory usage. Memory will be specific Used
classification , GC
and so on.
Dart DevTools
Memory tool is not perfect, Xcode
you can select a certain memory, see this piece of memory related to the main call stack, and call stack can click to jump to Xcode
the corresponding code, but Dart DevTools
do not have this function, and may Web
show form There are relationships.
Memory management Flutter
using GC
recovery speed may not be soon, iOS
in ARC
the reference count is based on immediate recovery. There are many other features, here is not described in detail, you can explore the students themselves.
Multi-instance
By instantiating the project is FlutterViewController
to show the controller Flutter
interface, the entire Flutter
page can be understood as a canvas page by constant change, change something on the canvas. Therefore, in the case of a single example, Flutter
the intermediate can not insert a page original page.
This time if we want to show in more places Flutter
pages, and these pages are not Flutter -> Flutter
coherent jump form, then how to achieve this scenario? Google
The proposal is to create a Flutter
multi-instance, and by passing different parameters to instantiate a different page. But this will cause very serious memory problems, and therefore it can not do.
Router
If you can not really create multiple instances of an object, it would need to implement multi-instance by other means. Flutter
Page display is actually not follow FlutterVC
to go, but followed the FlutterEngine
walk. So created once FlutterVC
after, it will be FlutterEngine
preserved, in other locations created FlutterVC
directly by FlutterEngine
creating a way, and after creating the jump operation.
During page switching, the channelMethod
calling Flutter
route side switching code, and the new page after the switching FlutterVC
is added to Native
the. This implementation is by Flutter
the Router
way of implementation, the following will introduce Router
two forms of static routing and dynamic routing.
Static Routing
A static route is MaterialApp
a provider of API
, routes
is essentially a Map
target, its composition is key
a unique identifier of the calling page, value
is the corresponding page Widget
.
When defining a static route, you can create Widget
incoming parameters, such as the examples of ContactWidget
it can pass the corresponding parameters in the past.
void main() {
runApp(
MaterialApp(
home: Page2(),
routes: {
'page1': (_) => Page1(),
'page2': (_) => Page2()
},
),
);
}
class Page1 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return ContactWidget();
}
}
class Page2 extends StatelessWidget {
@override
Widget build(BuildContext context) {
return HomeScreen();
}
}
复制代码
When the page jump through the Navigator
call, each call will re-create the corresponding Widget
. When calling pushNamed
function will pass a parameter, that is the definition of Map
the corresponding page of time key
.
Navigator.of(context).pushNamed('page1');
复制代码
Dynamic Routing
Static routing is not very flexible way, in terms of dynamic routing is relatively more flexible. Dynamic routing is not required preset routes
, you can directly call. And common push
difference is that, in the dynamic routing push
through the PageRouteBuilder
constructed push
object, Builder
the corresponding page construction method to perform a jump operation.
Binding said before channelMethod
, that is, channelMethod
the corresponding Callback
callback, performed Navigator
the push
function of receiving Native
the parameters passed to it and builds the corresponding Widget
page, Widget
back to the Builder
to complete the page jumping operation. So dynamic routing is very flexible.
Either through static routing or dynamic routing way to create, you can then
receive the return value of a function that returns a new page.
Navigator.of(context).push(PageRouteBuilder(
pageBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation) {
return ContactWidget('next page value');
}
transitionsBuilder: (BuildContext context, Animation<double> animation, Animation<double> secondaryAnimation, Widget child) {
return FadeTransition(
child: child,
opacity: animation,
);
}
)).then((onValue){
print('pop的返回值 $onValue');
});
复制代码
However, dynamic routing jump the way there are some problems, can lead to failure of the animation. So it is necessary to rewrite Builder
the transitionsBuilder
function to customize the transition animation.
Either through static routing or dynamic routing way to create, there will be some problems. Due to the newly created every time Widget
, so there will be a black screen problem when creating. And every time you create, it will lose the context of the current status of the last page, a new page is a time to come.
Reproduced in: https: //juejin.im/post/5d0b7015f265da1bc23f7e3a