Flutter- 插件开发:以微信 SDK 为例,android 音频面试题
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;});}
@overrideWidget build(BuildContext context) {return MaterialApp(home: Scaffold(appBar: AppBar(title: const Text('Plugin example app'),),body: Center(child: Text('Running on: $_platformVersion\n'),),),);}}
这里需要特别注意的就是?initPlatformState()?方法中对?Wechat.platformVersion?的调用,这里面的?Wechat?就是我们的插件,platformVersion?就是插件提供的?get?方法,跟着这个文件,找到?lib/wechat.dart?文件,代码如下:
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');return version;}}
在该文件中,可以看到 class Wechat 定义了一个 get 方法 platformVersion,它的函数体有点特别:
final String version = await _channel.invokeMethod('getPlatformVersion');return version;
我们的?version?是通过?_channel.invokeMethod('getPlatformVersion')?方法的调用得到的,这个?_channel?就是我们 Dart 代码与 原生代码进行通信的桥了,也是 Flutter 原生插件的核心(当然,如果你编写的插件并不需要原生代码相关的功能,那么,_channel?就是可有可无的了,比如我们可以写一个下面这样的方法,返回 两个数字?a?与?b?的和:
class Wechat {...static int calculate (int a, int b) {return a + b;}}
之后,修改 example/lib/main.dart 代码:
class _MyAppState extends State<MyApp> {String _platformVersion = 'Unknown';// 定义一个 int 型变量,用于保存计算结果 int _calculateResult;
@overridevoid initState() {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 的时候,计算一下 10 + 10 的结果_calculateResult = Wechat.calculate(10, 10);
setState(() {_platformVersion = platformVersion;});}
@overrideWidget 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: _calculateResult\n'),],),),),),);}}
支持原生编码提供的方法
很多时候,写插件,更多的是因为我们需要让应用能够调用原生代码提供的方法,怎么做呢?
Android 系统
打开?android/src/main/java/com/example/wechat/WechatPlugin.java
?文件,看如下代码:
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());}
@Overridepublic void onMethodCall(MethodCall call, Result result) {if (call.method.equals("getPlatformVersion")) {result.success("Android " + android.os.Build.VERSION.RELEASE);} else {result.notImplemented();}}}
还记得上面提到的?getPlatformVersion?吗?还记得?_channel?那么,是不是在这里面也看到的对应的存在?没错,?dart?中的?getPlatformVersion?通过?_channel.invokeMethod?发起一次请求,然后,Java?代码中的?onMethodCall?方法回被调用,该方法有两个参数:
MethodCall call:请求本身 Result result:结果处理方法然后通过?call.method?可以知到?_channel.invokeMethod?中的方法名,然后通过?result.success?回调返回成功结果响应。
registerWith
在上面还有一小段代码 registerWith,可以看到里面有一个调用:
final MethodChannel channel = new MethodChannel(registrar.messenger(), "wechat");channel.setMethodCallHandler(new WechatPlugin());
这里就是在注册我们的插件,将 wechat 注册成为我们的 channel 名,这样,才不会调用 alipay 插件的调用最后到了 wechat 插件这里。###iOS 系统同样的,这次我们打开 ios/Classes/WechatPlugin.m 文件:
#import "WechatPlugin.h"
@implementation WechatPlugin
(void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>)registrar {FlutterMethodChannel channel = [FlutterMethodChannelmethodChannelWithName:@"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
虽然语法有所不同,但是,可以看到,跟?android?的 Java 代码结构上几乎是一模一样的,首先?register?一个名为?wechat?的?channel,然后去?handleMethodCall,同样的通过?call.method 拿到方法名,通过?result?做出响应。
###小试牛刀接下来,我们将前面的?caculate?方法,移到原生代码中来提供(虽然这很没必要,但毕竟,只是为了演示嘛)。
###Android 在前面打开的?android/src/main/java/com/example/wechat/WechatPlugin.java?文件中,修改?onMethodCall?方法:
@Overridepublic 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();}}
添加了?call.method.equals("calculate")?判断,这里面具体的过程是:
调用?call.argument()?方法,可以取得由?wechat.dart?传递过来的参数计算结果调用?result.success()?响应结果然后,我们需要在?lib/wechat.dart?中修改?calculate?方法的实现,代码如下:
static Future<int> calculate (int a, int b) async {final String result = await _channel.invokeMethod('calculate', {'a': a,'b': b});return int.parse(result);}
由于?_channel.invokeMethod?是一个异步操作,所以,我们需要将?calculate?的返回类型修改为?Future,同时加上?async,此时我们就可以直接使用?await?关键字了,跟?JavaScript?中的?await?一样,让我们用同步的方式编写异步代码,在新版的?calculate?代码中,我们并没有直接计算?a+b?的结果,而是调用?_channel.invokeMethod?方法,将?a?与?b?传递给了?Java?端的?onMethodCall?方法,然后返回该方法返回的结果。_channel.invokeMethod
该方法接受两个参数,第一个定义一个方法名,它是一个标识,简单来说,它告诉原生端的代码,我们这次是要干什么,第二个参数是一个?Map<String, dynamic>?型数据,是参数列表,我们可以在原生代码中获取到。
接着,我们需要更新一下对该方法的调用了,回到?example/lib/main.dart?中,修改成如下调用:
_calculateResult = await Wechat.calculate(10, 10);
因为我们现在的?calculate
?方法已经是一个异步方法了。
iOS
如果我们的插件需要支持?Android
?与?IOS
?两端,那么需要同步的在?ios
?中实现上面的方法,打开?ios/Classes/WechatPlugin.m
?文件,作如下修改:
(void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {NSDictionary *arguments = [call arguments];if ([@"getPlatformVersion" isEqualToString:call.method]) {result(
《Android 学习笔记总结+最新移动架构视频+大厂安卓面试真题+项目实战源码讲义》
【docs.qq.com/doc/DSkNLaERkbnFoS0ZF】 完整内容开源分享
[@"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);}}
实现过程与?java
?端保持一致即可。
添加第三方 SDK
我们的插件是可以提供微信的分享相关功能的,所以,肯定需要用到第三方 SDK,还是从 Android 开始。
Android 端 WechatSDK
按?官方接入指南?所述,我们需要添加依赖:
dependencies {compile 'com.tencent.mm.opensdk:wechat-sdk-android-with-mta:+'}
或
dependencies {compile 'com.tencent.mm.opensdk:wechat-sdk-android-without-mta:+'}
前者带有统计功能,这很简单,打开 android/build.gradle 文件 ,在最下方粘贴以上片段即可:
...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:+'}
然后,回到 WechatPlugin.java 文件,先添加一个 register 方法,它将我们的 Appid 注册给微信,还是接着前面的 onMethodCall 中的 if 判断:
...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));
最后
现在都说互联网寒冬,其实无非就是你上错了车,且穿的少(技能),要是你上对车,自身技术能力够强,公司换掉的代价大,怎么可能会被裁掉,都是淘汰末端的业务 Curd 而已!现如今市场上初级程序员泛滥,这套教程针对 Android 开发工程师 1-6 年的人员、正处于瓶颈期,想要年后突破自己涨薪的,进阶 Android 中高级、架构师对你更是如鱼得水!
为什么某些人会一直比你优秀,是因为他本身就很优秀还一直在持续努力变得更优秀,而你是不是还在满足于现状内心在窃喜!
Android 架构师之路很漫长,一起共勉吧!
评论