往期回顾
从零开始的 Flutter 之旅: StatelessWidget
从零开始的 Flutter 之旅: StatefulWidget
从零开始的 Flutter 之旅: InheritedWidget
从零开始的 Flutter 之旅: Provider
从零开始的 Flutter 之旅: Navigator
在 flutter_github 有这么一个场景:通过 authorization 认证形式进行登录。而 authorization 的具体登录模式是,通过跳转一个网页链接进行 github 受权登录,胜利之后会携带对应的 code 到指定客户端中,而后客户端能够通过这个 code 来进行 oauth 受权登录,胜利之后客户端能够拿到该账户的 token,所以之后的 github 操作都能够通过该 token 来进行申请。因为 token 是有时效性,同时也能够手动解除受权,所以绝对于在客户端进行账户明码登录来说更加平安。
那么要实现下面这个场景,Flutter 就须要与原生客户端进行通信,拿到返回的 code,而后再到 Flutter 中进行 oauth 受权登录申请。
通信形式能够应用 MethodChannel,这个就是明天的主题。
OAuth App
authorization 认证的原理曾经晓得了,上面间接来看实现计划。
首先咱们须要一个 OAuth App 用来提供用户通过 github 受权的利用。
这个在 github 上能够间接注册的
在注册的 OAuth App 时会有一个 Authorization callback URL
必填项。这个 callback url 的作用就是当你通过该链接认证通过后会以 App Link 的形式应用该 url 跳转到对应的 App 利用,同时返回认证胜利的 code。这里将其定义为REDIRECT_URI
注册胜利之后,咱们拿到它的 Client ID
、Client Secret
与Authorization callback URL
,拼接成上面的连贯
const String URL_AUTHORIZATION =
'https://github.com/login/oauth/authorize?client_id=$CLIENT_ID&redirect_uri=$REDIRECT_URI&scope=user%20repo%20notifications%20';
有了跳转到内部的认证链接之后,上面就是在利用中实现这个跳转认证流程。
url_launcher
首先须要跳转内部浏览器拜访下面的 authorization 链接。这一步的实现须要借助url_launcher
,它可能帮忙咱们查看链接是否无效,同时启动内部浏览器进行跳转。
在应用之前须要在 pubspec.yaml
中增加依赖
dependencies:
flutter:
sdk: flutter
http: 0.12.0+4
dio: 3.0.7
shared_preferences: 0.5.6+1
url_launcher: 5.4.1
...
依赖胜利之后,应用 canLaunch()
来查看链接的有效性;launch()
来启动跳转
authorization() {return () async {FocusScope.of(context).requestFocus(FocusNode());
if (await canLaunch(URL_AUTHORIZATION)) {
// 为设置 forceSafariVC,IOS 默认会关上 APP 外部 WebView
// 而 APP 外部 WebView 不反对重定向跳转到 APP
await launch(URL_AUTHORIZATION, forceSafariVC: false);
} else {throw 'Can not launch $URL_AUTHORIZATION)';
}
};
}
Scheme
通过 authorization()
办法能够胜利跳转到内部浏览器进行登录授认证。受权胜利之后会返回到之前的 app,具体页面门路与链接中配置的 REDIRECT_URI
无关。
const String REDIRECT_URI = 'github://login';
这里定义了一个Scheme
,为了可能胜利返回到客户端指定的页面,咱们须要为 Android 与 IOS 配置对应的 Scheme。
Android
找到 AndroidManifest
文件,在 activity
便签下增加 intent-filter
属性
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data
android:host="login"
android:scheme="github" />
</intent-filter>
后面的 action
与category
配置是固定的,如果须要反对不同的 scheme
,次要批改的是data
中的配置。
将 scheme
与host
别离对应到 REDIRECT_URI
中的数值。
IOS
找到 info.plist
文件,增加 URL types
便签,在它的 item 下配置对应的 URL identifier
与URL Schemes
配置完 scheme 之后,就可能失常返回到对应的客户端页面。
接下来须要思考的是,如何拿到返回的 code 值
MethodChannel
这个时候明天的配角就该上场了。
MethodChannel
简略的说就是 Flutter
提供与客户端通信的渠道,应用时相互约定一个渠道 name
与对应的调用客户端指定办法的method
。
所以咱们先来约定好这两个值
const String METHOD_CHANNEL_NAME = 'app.channel.shared.data';
const String CALL_LOGIN_CODE = 'getLoginCode';
而后通过 MethodChannel
来获取对应的渠道
callLoginCode(AppLifecycleState state) async {if (state == AppLifecycleState.resumed) {final platform = const MethodChannel(METHOD_CHANNEL_NAME);
final code = await platform.invokeMethod(CALL_LOGIN_CODE);
if (code != null) {_getAccessTokenFromCode(code);
}
}
}
应用 invokeMethod
来调用客户端对应的办法,这里是用来获取受权胜利后返回客户端的 code。
这是 Flutter 调用客户端办法的步骤,上面再看客户端的实现
Android
首先咱们将约定好的渠道名称与回调办法名定义为常量
object Constants {
const val AUTHORIZATION_CODE = "code"
const val METHOD_CHANNEL_NAME = "app.channel.shared.data"
const val CALL_LOGIN_CODE = "getLoginCode"
}
在之前咱们曾经在 AndroidManifest.xml
中定义的 scheme,所以认证胜利后回返回客户端的 MainActivity
页面,同时回调 onNewIntent
办法。
所以获取返回 code 的形式能够在 onNewIntent
中进行,同时还须要建设对应的 MethodChannel
与提供回调的办法。具体实现如下:
class MainActivity : FlutterActivity() {
private var mAuthorizationCode: String? = null
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {GeneratedPluginRegistrant.registerWith(flutterEngine)
setupMethodChannel()}
override fun onNewIntent(intent: Intent) {super.onNewIntent(intent)
getExtra(intent)
}
private fun getExtra(intent: Intent?) {
// from author login
mAuthorizationCode = intent?.data?.getQueryParameter(Constants.AUTHORIZATION_CODE)
}
private fun setupMethodChannel() {MethodChannel(flutterEngine?.dartExecutor, Constants.METHOD_CHANNEL_NAME).setMethodCallHandler { call, result ->
if (call.method == Constants.CALL_LOGIN_CODE && !TextUtils.isEmpty(mAuthorizationCode)) {result.success(mAuthorizationCode)
mAuthorizationCode = null
}
}
}
}
MethodChannel
建设渠道,setMethodCallHandler
来响应 Flutter 中须要调用的办法。通过判断回调的办法名称,即之前在 Flutter 中约定的CALL_LOGIN_CODE
。来执行对应的逻辑
因为咱们须要返回的 code 值,只需通过 result
的success
办法,将获取到的 code 传递过来即可。之后 Flutter 就可能获取到该值。
IOS
在 AppDelegate.swift
中定义一个 methodChannel,应用约定好的 name。
methodChannel 的创立 IOS 是通过 FlutterMethodChannel.init
来生成。之后的回调与 Android 的根本相似
@UIApplicationMain
@objc class AppDelegate: FlutterAppDelegate {var paramsMap: Dictionary<String, String> = [:]
override func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?
) -> Bool {GeneratedPluginRegistrant.register(with: self)
let controller: FlutterViewController = window?.rootViewController as! FlutterViewController
let methodChannel = FlutterMethodChannel.init(name: "app.channel.shared.data", binaryMessenger: controller.binaryMessenger)
methodChannel.setMethodCallHandler {(call, result) in
if "getLoginCode" == call.method && !self.paramsMap.isEmpty {result(self.paramsMap["code"])
self.paramsMap.removeAll()}
}
return super.application(application, didFinishLaunchingWithOptions: launchOptions)
}
override func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let absoluteString = url.absoluteURL.absoluteString
let urlComponents = NSURLComponents(string: absoluteString)
let queryItems = urlComponents?.queryItems
for item in queryItems! {paramsMap[item.name] = item.value
}
return true
}
}
在 setMethodCallHandler
中判断回调的办法是否与约定的办法名统一,如果统一再通过 result
办法将 code 传递给 Flutter。
至此 Android 与 IOS 都与 Flutter 建设了通信,它们之间的桥梁就是通过 MethodChannel 来搭建的。
最初 code 传回到 Flutter 之后,咱们再将 code 进行申请获取到对应的 token。
到这里整个受权认证就实现了,之后咱们就能够通过 token 来申请用户相干的接口,获取对应的数据。
token 的获取与相干接口的调用能够通过查看 flutter_github 源码获取
flutter_github
flutter_github,这是一个基于 Github Open Api 开发的 Flutter 版本的 Github 客户端。该我的项目次要是用来练习 Flutter,感兴趣的能够退出一起来学习,如果有帮忙的话也请不要悭吝你的关注。
当然如果你想理解 Android 原生,AwesomeGithub 是一个不错的抉择。它是 flutter_github 的纯 Android 版本。
如果你喜爱我的文章模式,或者对我接下来的文章感兴趣,你能够关注我的微信公众号:【Android 补给站】
或者扫描下方二维码,与我建设无效的沟通,同时可能更不便的收到相干的技术推送。