Flutter mobile end combat manuals

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 iOSand Flutterwhen mixed, iOSthan Androidaccess slightly complicated, but also good. There are now a lot of access to Flutterprograms, but most are stereotyped copy of each other, no meaning.

Conducted Flutterbefore mixed, there are some necessary documents.

  1. xcode_backend.shFiles, configuration fluttertime environment by Flutterproviding toolkits.
  2. xcconfigEnvironment variable file, Flutterautomatically generated project, each project is different.

xcconfig file

xcconfigIt is the Xcodeconfiguration file, Flutterin which some basic configuration information and the path, access Flutterpre-need to first xcconfigaccess in, otherwise some paths and other information will be wrong or missing.

FlutterThe xcconfigconsists of three files, Debug.xcconfig, , Release.xcconfig, Generated.xcconfigthese 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 Configurationsset up in xcconfigthe file, since each Targetkind of environment can have only one xcconfigfile, it can be an existing xcconfigfile importintroduced Generated.xcconfigfiles, and no need to distinguish the environment.

Script file

xcode_backend.shScript files used to build and export the Flutterproduct, which is the Flutterdevelopment kit provided to us by default. In the works require Targetthe Build Phasesaddition of a Run Scriptfile and paste the following script code. It should be noted, do not forget the previous /bin/shoperation, 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.shthree types of parameters, build, thin, embed, thindoes not mean much, the other two are responsible for building and exporting.

Mixed-use development

You can then Xcodecompile 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 Flutterfile folder, which will contain two framework, this folder is Fluttercompiled product, we will be dragged into the overall project to this folder.

This time we can iOSadd project Fluttercodes, the following is the detailed steps.

  1. The AppDelegateintegration of change FlutterAppDelegate, and the need to follow the FlutterAppLifeCycleProvideragency.
#import <Flutter/Flutter.h>
#import <UIKit/UIKit.h>

@interface AppDelegate : FlutterAppDelegate <FlutterAppLifeCycleProvider>

@end
复制代码
  1. Create an FlutterPluginAppLifeCycleDelegateinstance of an object, the object is responsible for managing Flutterthe life cycle, and from Platformthe receiving side AppDelegateof the event. I will declare it as a direct property, in AppDelegatethe 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;
}
复制代码
  1. You can then join Flutterthe way the code is added is also very simple, straightforward example of a FlutterViewControllercontroller can be, do not need to pass additional parameters into account (here is not considered multi-instance issues).
FlutterViewController *flutterViewController = [[FlutterViewController alloc] init];
复制代码

FlutterThink 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.

  1. Wrong path, not read xcode_backend.shdocuments. This is because the environment variable is FLUTTER_ROOTnot acquired, FLUTTER_ROOTconfiguration Generated.xcconfig, you can look at the document in question is not configured.
  2. lipo info *** arm64An error like this, usually because the xcode_backend.shscript causes, you can check the FLUTTER_ROOTenvironment variable is correct.
  3. This problem usually because of the following rights cause, you can view Build Phasesthe script writing is not a problem.
***/flutter_tools/bin/xcode_backend.sh: Permission denied
复制代码

Mixed-use development

In carrying mixed, Flutterthere is a great advantage is that if the Fluttercode is wrong, will not lead to the collapse of native applications. When Flutterthe 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 Platformtreatment, Flutterthe side is only responsible to Platformrequest and brought to use.

This process involves the issue of data interaction ends, Flutterfor mixed given two options, MethodChanneland 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 MethodChannelto complete all requirements.

Flutter to Native

The following is a Fluttercall Nativecode, in Nativethrough the FlutterMethodChannelsetting specified callback code, and the process parameters and receiving. By the Flutterby MethodChannelto Nativeinitiate calls, and pass the corresponding parameters.

In the code Flutterto build the data model good side, then call MethodChannelthe invokeMethodtriggered Nativecallbacks. NativeGet Flutterpass over the data, parse and execute playback operation, playback status code will then callback to Flutterside, 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

NativeCalling Fluttercode and Fluttercalls Nativesubstantially similar, just call and set up different roles callback. Also, Flutterdue to receive Nativethe callback messages, you need to register a callback, the Nativelaunch of the Fluttercall and pass parameters.

NativeAnd Flutterthe need to set up a call each other names, each name corresponds to a MethodChanneltarget, each object can initiate multiple calls to different call to invokeMethodmake 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 iOSand Androiddevelopment in their respective compilers provide a good set of debugging tools, facilitate memory, performance, and other debug view. FlutterAlso provides debugging tools and commands, based on the following VSCodecompiler is concerned about Flutterdebugging, relatively speaking Android Studiodebugging features provided may be some more.

Performance Tuning

VSCodeIt supports some simple command-line debugger commands, the program is running in Command Palettethe command line input panel performance, and select the Toggle Performance Overlaycommand. 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

VSCodeTo Flutterprovide 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 DevToolslater, in the App running state, in VSCodethe 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 DevToolsthe main interface, I am running a micro-channel interface similar to the App. From Inspectorcan see the view of the structure of the page, Android Studioit 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, colorand so on, this feature is very useful.

I am running device Xcodesimulator, if you want to switch Androidin Material Design, click on the iOSbutton to directly change the device. When it comes to just above view memory performance panel, click on the iOSbutton next Performance Overlayto appear.

Select Widget

If you want to know the Dart DevToolsnode selected, which corresponds to a specific control, you can select Select Widget Modethe control highlight on the screen is selected.

Debug Paint

Click Debug Paintallows each control are highlighted by this mode you can see ListViewthe distance between the sliding direction, and the size and control of each control.

In addition, you can also select Paint Baselinethe highlighted bottom line of all controls, functions and Debug Paintsimilar, not narrative.

Memory

Dart DevToolsMemory 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 Usedclassification , GCand so on.

Dart DevToolsMemory tool is not perfect, Xcodeyou can select a certain memory, see this piece of memory related to the main call stack, and call stack can click to jump to Xcodethe corresponding code, but Dart DevToolsdo not have this function, and may Webshow form There are relationships.

Memory management Flutterusing GCrecovery speed may not be soon, iOSin ARCthe 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 FlutterViewControllerto show the controller Flutterinterface, the entire Flutterpage can be understood as a canvas page by constant change, change something on the canvas. Therefore, in the case of a single example, Flutterthe intermediate can not insert a page original page.

This time if we want to show in more places Flutterpages, and these pages are not Flutter -> Fluttercoherent jump form, then how to achieve this scenario? GoogleThe proposal is to create a Fluttermulti-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. FlutterPage display is actually not follow FlutterVCto go, but followed the FlutterEnginewalk. So created once FlutterVCafter, it will be FlutterEnginepreserved, in other locations created FlutterVCdirectly by FlutterEnginecreating a way, and after creating the jump operation.

During page switching, the channelMethodcalling Flutterroute side switching code, and the new page after the switching FlutterVCis added to Nativethe. This implementation is by Flutterthe Routerway of implementation, the following will introduce Routertwo forms of static routing and dynamic routing.

Static Routing

A static route is MaterialAppa provider of API, routesis essentially a Maptarget, its composition is keya unique identifier of the calling page, valueis the corresponding page Widget.

When defining a static route, you can create Widgetincoming parameters, such as the examples of ContactWidgetit 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 Navigatorcall, each call will re-create the corresponding Widget. When calling pushNamedfunction will pass a parameter, that is the definition of Mapthe 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 pushdifference is that, in the dynamic routing pushthrough the PageRouteBuilderconstructed pushobject, Builderthe corresponding page construction method to perform a jump operation.

Binding said before channelMethod, that is, channelMethodthe corresponding Callbackcallback, performed Navigatorthe pushfunction of receiving Nativethe parameters passed to it and builds the corresponding Widgetpage, Widgetback to the Builderto complete the page jumping operation. So dynamic routing is very flexible.

Either through static routing or dynamic routing way to create, you can thenreceive 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 Builderthe transitionsBuilderfunction 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

Guess you like

Origin blog.csdn.net/weixin_33721427/article/details/93180679