Just like React Native, the Flutter Plugin is a good way to use the Flutter Plugin if you need to invoke third-party library methods or have some functionality that needs to be provided using Native development. It is essentially a Dart Package. Unlike other packages, however, there are two special folders in the Flutter plugin: For Android and ios, if we need to write Java, Kotlin, or Object-C, and Swift code, we need to do it in those two folder projects, and then map the methods developed in native code to DART using the corresponding methods.
Create a plug-in directory
To develop plug-ins, you can quickly start with the plugin template using the following code:
flutter create --template=plugin wechat
Copy the code
In the above code, a package named wechat is created using the Plugin template. After creation, the directory structure of the whole project is provided, and some basic development examples are provided officially.
The directory structure
-android // Android related native code directory -ios // ios related native code directory -lib // Dart code directory -example // A complete call to the Flutter App that we are developing Pubspec.yaml // Project configuration fileCopy the code
Dart starts with example/lib/main.dart. After developing our application, we should first look at the files that flutter generates for us. Open the example/lib/main.dart code as follows
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:flutter/services.dart';
import 'package:wechat/wechat.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
_MyAppState createState() => _MyAppState();
}
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown';
@override
void initState() {
super.initState();
initPlatformState();
}
// Platform messages are asynchronous, so we initialize in an async method.
Future<void> initPlatformState() async {
String platformVersion;
// Platform messages may fail, so we use a try/catch PlatformException.
try {
platformVersion = await Wechat.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
// If the widget was removed from the tree while the asynchronous platform
// message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance.
if(! mounted)return;
setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),),),); }}Copy the code
In particular, the initPlatformState() method calls Wechat. PlatformVersion, where Wechat is our plugin and platformVersion is the get method provided by the plugin. Follow this file to the lib/wechat. Dart file as follows:
import 'dart:async';
import 'package:flutter/services.dart';
class Wechat {
static const MethodChannel _channel =
const MethodChannel('wechat');
static Future<String> get platformVersion async {
final String version = await _channel.invokeMethod('getPlatformVersion');
returnversion; }}Copy the code
In this file, you can see that class Wechat defines a get method, platformVersion, which has a somewhat special function body:
final String version = await _channel.invokeMethod('getPlatformVersion');
return version;
Copy the code
Our version is obtained by calling the _channel.invokemethod (‘getPlatformVersion’) method. This _channel is the bridge through which our Dart code communicates with the native code. _channel is also the core of the Flutter native plugin (of course, if you write a plugin that doesn’t need any of the functionality associated with the native code, then _channel is optional. For example, we could write a method that returns the sum of two numbers a and B:
class Wechat {
...
static int calculate (int a, int b) {
returna + b; }}Copy the code
Dart /lib/main.dart
class _MyAppState extends State<MyApp> {
String _platformVersion = 'Unknown'; // Define a variable of type int to hold the result int _calculateResult; @override voidinitState() {
super.initState();
initPlatformState();
}
Future<void> initPlatformState() async {
String platformVersion;
try {
platformVersion = await Wechat.platformVersion;
} on PlatformException {
platformVersion = 'Failed to get platform version.';
}
if(! mounted)return; // init to calculate the result of 10 + 10 _calculateResult = calculate. calculate(10, 10);setState(() {
_platformVersion = platformVersion;
});
}
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
appBar: AppBar(
title: const Text('Plugin example app'),), body: Container(padding: EdgeInsets. All (16.0), Child: SingleChildScrollView(Child: Column(children: <Widget>[ Text('Running on: $_platformVersion\n'), // Print the result Text('Calculate Result: $_calculateResult\n'),],),),),),); }}Copy the code
Support for methods provided by native coding
A lot of times, we write plug-ins because we need to be able to call the methods that native code provides. How do we do that?
The Android system
Open the android/SRC/main/Java/com/example/wechat/WechatPlugin. Java file, see the following code:
package com.example.wechat;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/** WechatPlugin */
public class WechatPlugin implements MethodCallHandler {
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel = new MethodChannel(registrar.messenger(), "wechat");
channel.setMethodCallHandler(new WechatPlugin());
}
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else{ result.notImplemented(); }}}Copy the code
Remember getPlatformVersion mentioned above? Remember _channel so, does that correspond to something you see in here? That’s right, getPlatformVersion in Dart makes a request via _channel.invokeMethod, and the onMethodCall method in Java code is called back with two parameters:
MethodCall: the request itself Result Result: Method then knows the name of the method in _channel.invokeMethod and returns a success result response via the result.success callback.
registerWith
There is also a little bit of registerWith code above, where you can see a call:
final MethodChannel channel = new MethodChannel(registrar.messenger(), "wechat");
channel.setMethodCallHandler(new WechatPlugin());
Copy the code
Here we are registering our plug-in, and we will register wechat as our channel name, so that the call of Alipay plug-in will not end up here.
iOS
Again, this time we open the ios/Classes/WechatPlugin m file:
#import "WechatPlugin.h"
@implementation WechatPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel
methodChannelWithName:@"wechat"
binaryMessenger:[registrar messenger]];
WechatPlugin* instance = [[WechatPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else {
result(FlutterMethodNotImplemented);
}
}
@end
Copy the code
The syntax is different, but the Java code structure is almost the same as android’s. First register a channel named wechat, then go to handleMethodCall, Call method to get the method name and respond to result.
A profound
Next, we move the previous caculate method into native code to provide it (it’s not necessary, but after all, it’s just for demonstration purposes).
Android
Open in front of the android/SRC/main/Java/com/example/wechat/WechatPlugin. Java file, modify onMethodCall method:
@Override
public void onMethodCall(MethodCall call, Result result) {
if (call.method.equals("getPlatformVersion")) {
result.success("Android " + android.os.Build.VERSION.RELEASE);
} else if (call.method.equals("calculate")) {
int a = call.argument("a");
int b = call.argument("b");
int r = a + b;
result.success("" + r);
} else{ result.notImplemented(); }}Copy the code
Add call.method.equals(“calculate”) to calculate.
Call the call.argument() method to get the calculation result of the argument passed in from weik.dart. Call result.success() and then, We need to modify the calculate method implementation in lib/wechat. Dart as follows:
static Future<int> calculate (int a, int b) async {
final String result = await _channel.invokeMethod('calculate', {
'a': a,
'b': b
});
return int.parse(result);
}
Copy the code
Since _channel.invokeMethod is an asynchronous operation, we need to change the calculate return type to Future and add async so we can use the await keyword directly. As with await in JavaScript, let’s write asynchronous code synchronously. In the new Calculate code, instead of directly calculating the result of a+b, we call the _channel.invokemethod method, A and B are passed to the Java-side onMethodCall method, and the result returned by that method is returned. _channel.invokeMethod
This method takes two arguments. The first defines a method name, which is an identifier that, in a nutshell, tells the native code what we’re doing this time. The second argument is a Map<String dynamic> data, which is a list of parameters that we can get in the native code.
Dart (); dart (); dart (); dart (); dart ();
_calculateResult = await Wechat.calculate(10, 10);
Copy the code
Because our calculate method is already an asynchronous one.
iOS
If our plugin needs to support Android and IOS at both ends, so need to be synchronized in the IOS implementation of the above methods, open the IOS/Classes/WechatPlugin m file, make the following changes:
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
NSDictionary *arguments = [call arguments];
if ([@"getPlatformVersion" isEqualToString:call.method]) {
result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]);
} else if ([@"calculate" isEqualToString:call.method]) {
NSInteger a = [arguments[@"a"] intValue];
NSInteger b = [arguments[@"b"] intValue];
result([NSString stringWithFormat:@"%d", a + b]);
} else{ result(FlutterMethodNotImplemented); }}Copy the code
The implementation process should be consistent with the Java side.
Adding a third-party SDK
Our plug-in can provide sharing related functions of wechat, so we definitely need to use the third-party SDK and start from Android.
The Android end WechatSDK
As stated in the official access guide, we need to add dependencies:
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
Copy the code
or
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'
}
Copy the code
The former comes with statistics. This is as simple as opening the Android /build.gradle file and pasting the above snippet at the bottom:
. android { compileSdkVersion 27 defaultConfig { minSdkVersion 16testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
lintOptions {
disable 'InvalidPackage'
}
}
dependencies {
compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'
}
Copy the code
Then, go back to the wechatplugin.java file and add a register method that registers our Appid with wechat.
. import com.tencent.mm.opensdk.openapi.WXAPIFactory; .else if (call.method.equals("register")) {
appid = call.argument("appid");
api = WXAPIFactory.createWXAPI(context, appid, true); result.success(api.registerApp(appid)); }...Copy the code
Then go back to lib/wechat. Dart and add the appropriate call:
. /// Register app to Wechat with [appid] static Future<dynamic> register(String appid) async { var result = await _channel.invokeMethod('register',
{
'appid': appid
}
);
returnresult; }...Copy the code
At this point, in our example, we can call the Wechat. Register method to register the application
ios
As described in the official ios Access Guide, we can add dependencies via POD:
pod 'WechatOpenSDK'
Copy the code
Open up ios/wechat. Podspec and you’ll see the following:
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html
#
Pod::Spec.new do |s|
s.name = 'wechat'
s.version = '0.0.1'
s.summary = 'A new flutter plugin project.'
s.description = <<-DESC
A new flutter plugin project.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '.. /LICENSE' }
s.author = { 'Your Company'= >'[email protected]' }
s.source = { :path => '. ' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.ios.deployment_target = '8.0'
end
Copy the code
Note that the third line of s.dependency specifies that we rely on Flutter. If there are other dependencies, add a line here:
. s.public_header_files ='Classes/**/*.h'
s.dependency 'Flutter'
s.dependency 'WechatOpenSDK'
s.ios.deployment_target = '8.0'
end
Copy the code
Then open the ios/Classes/WechatPlugin. H file, modify the following:
#import <Flutter/Flutter.h>
#include "WXApi.h"
@interface WechatPlugin : NSObject<FlutterPlugin, WXApiDelegate>
@end
Copy the code
Back to ios/Classes/WechatPlugin. J m, then the front if conditions continue to add:
. // Register app to Wechat with appidelse if ([@"register" isEqualToString:call.method]) {
[WXApi registerApp:arguments[@"appid"]]. result(nil); }...Copy the code
At this point, our plug-in has already supported wechat SDK registration to wechat function, more implementation, this article will not discuss, interested, you can directly download the complete project, the following are more similar implementation, the only need is that you need to have a certain Java coding and Objective-C coding ability.