本機號碼一鍵登陸基本成爲各個 APP 的標配了。php
傳統的手機驗證碼登陸方式:html
- 輸入手機號;
- 前端判斷手機號是否有效;
- 後臺判斷手機號是否有效;
- 藉助第三方下發手機驗證碼;
- 前端有一個倒計時,防止驗證碼過時輸入;
- 手機收到驗證碼;
- 複製粘貼輸入驗證碼校驗;
- 將信息發給後臺接口,驗證手機號和驗證碼是否正確,而後纔是註冊和登陸流程,下發認證 Auth 信息。
這一套流程下來足夠費勁了。而上述的「本機號碼一鍵登陸」徹底無感,只要一點按鈕,全部操做一步到位。前端
今天咱們來講一說如何利用「極光」作到「本機號碼一鍵登陸」的。android
開通「極光認證」,須要先完成實名認證,實名認證後能夠領取 1,000 次極光認證禮包。ios
認證成功後,填入 android 和 iOS 包名、簽名等信息。git
開通後,便可領取無償使用次數。github
注:簽名生成工具 apk 包下載連接:res.wx.qq.com/open/zh_CN/…web
看過以前文章的朋友應該知道咱們公司的 APP 是基於 Flutter 開發的,並且用到極光的推送插件:《推薦一款 Flutter Push 推送功能插件》mp.weixin.qq.com/s/l0_lghnp7…。json
這裏咱們仍是使用極光認證提供的 Flutter 插件,根據官方提供的安裝方法有 github 源代碼集成和 pub 集成,這裏我推薦 pub 集成方法:api
dependencies:
jverify: 0.6.1
複製代碼
有了插件,接下來就能夠寫功能了。先來看看插件都提供哪些功能,這裏咱們主要看 Flutter 插件源碼,
具體包括:
- setup
- setDebugMode
- isInitSuccess
- checkVerifyEnable
- getToken
- verifyNumber
- loginAuth
- loginAuthSyncApi
- preLogin
- dismissLoginAuthView
- setCustomUI (註釋掉了該功能)
- setCustomAuthViewAllWidgets
- clearPreLoginCache
- setCustomAuthorizationView
極光認證提供了兩個方向性的功能:驗證手機號和一鍵登陸功能,今天咱們主要是用到一鍵登陸功能,整個插件使用流程大體是這樣的:
主要用到的核心功能有:
- setup
- setDebugMode
- isInitSuccess
- checkVerifyEnable
- preLogin
- setCustomAuthViewAllWidgets
- loginAuth
每一個功能都挺好理解的,能夠過一遍代碼。
/// 統一 key
final String f_result_key = "result";
/// 錯誤碼
final String f_code_key = "code";
/// 回調的提示信息,統一返回 flutter 爲 message
final String f_msg_key = "message";
/// 運營商信息
final String f_opr_key = "operator";
final Jverify jverify = new Jverify();
複製代碼
因爲個人 APP 是 Flutter 一套開發的,因此在用 setup()
時帶上 appKey
和 channel
屬性,Android 則在配置文件中配置。
在 /android/app/build.gradle 中添加極光上建立應用的配置信息,我以前用到極光推送了,用的同一個應用。
// 註冊極光認證
jverify.setup(
appKey: "6592925ae1*****658473",//"你本身應用的 AppKey",
channel: "devloper-default");
複製代碼
這個簡單,就是是否須要 debug 模式,在開發中建議打開,你也能夠建立一個全局變量,在開發中默認打開,在打包 release 模式下是關閉的,避免在 APP 開發過程和打包過程當中反覆去修改這個狀態
jverify.setDebugMode(isDebug); // 是否打開調試模式
複製代碼
判斷 sdk 初始換是否成功:
jverify.isInitSuccess().then((map) {
bool result = map[f_result_key];
setState(() {
if (result) {
_result = "sdk 初始換成功";
}else {
_result = "sdk 初始換失敗";
}
});
複製代碼
判斷當前的手機網絡環境是否可使用認證。
jverify.checkVerifyEnable().then((map) {
bool result = map[f_result_key];
setState(() {
if (result) {
_result = "當前網絡環境【支持認證】!";
}else {
_result = "當前網絡環境【不支持認證】!";
}
});
});
複製代碼
以上的幾個方法基本都是在 sdk 初始化和驗證是否能夠知足一鍵登陸條件。
當環境知足一鍵登陸後,咱們就開始進行一鍵登陸操做了,但操做以前,官網提示咱們最好先進行 preLogin
SDK 一鍵登陸預取號操做,理由是:
sdk會緩存預取號結果,提高以後受權頁拉起速度。因此建議拉起受權頁前,好比在開屏頁或者業務入口頁預先調用此接口進行預取號。
請求成功後,不要頻繁重複調用。
不要在預取號回調中重複調用預取號或者拉起受權頁接口。
jverify.preLogin().then((map) {
int code = map[f_code_key];
String message = map[f_msg_key];
setState(() {
_loading = false;
_result = "[$code] message = $message";
});
});
複製代碼
好了,這時候是萬事具有,只欠東風了,但,就如咱們開篇的截圖,咱們必需要有一個界面,用於提示咱們的用戶,咱們須要開始一鍵登陸操做,並獲得他們的承認,以及獲取我的信息的說明,也就須要下一個功能的定製化實現。
jverify.setCustomAuthorizationView(true, uiConfig, landscapeConfig: uiConfig);
複製代碼
這裏須要注意的是:
Android 橫屏的 UI 配置,只有當 isAutorotate=true 時必須傳(也就是方法中的第一個參數),而且該配置只生效在 Android,iOS 使用 portraitConfig 的約束適配橫屏。
橫豎屏的 UI 則須要根據本身的 APP 設計風格來定製,demo 中提供簡要的配置:
final screenSize = MediaQuery.of(context).size;
final screenWidth = screenSize.width;
final screenHeight = screenSize.height;
bool isiOS = Platform.isIOS;
/// 自定義受權的 UI 界面,如下設置的圖片必須添加到資源文件裏,
/// android項目將圖片存放至drawable文件夾下,可以使用圖片選擇器的文件名,例如:btn_login.xml,入參爲"btn_login"。
/// ios項目存放在 Assets.xcassets。
///
JVUIConfig uiConfig = JVUIConfig();
//uiConfig.authBackgroundImage = ;
//uiConfig.navHidden = true;
uiConfig.navColor = Colors.red.value;
uiConfig.navText = "coding01登陸";
uiConfig.navTextColor = Colors.blue.value;
uiConfig.navReturnImgPath = "return_bg";//圖片必須存在
uiConfig.logoWidth = 100;
uiConfig.logoHeight = 100;
//uiConfig.logoOffsetX = isiOS ? 0 : null;//(screenWidth/2 - uiConfig.logoWidth/2).toInt();
uiConfig.logoOffsetY = 10;
uiConfig.logoVerticalLayoutItem = JVIOSLayoutItem.ItemSuper;
uiConfig.logoHidden = false;
uiConfig.logoImgPath = "logo";
uiConfig.numberFieldWidth = 200;
uiConfig.numberFieldHeight = 40 ;
//uiConfig.numFieldOffsetX = isiOS ? 0 : null;//(screenWidth/2 - uiConfig.numberFieldWidth/2).toInt();
uiConfig.numFieldOffsetY = isiOS ? 20 : 120;
uiConfig.numberVerticalLayoutItem = JVIOSLayoutItem.ItemLogo;
uiConfig.numberColor = Colors.blue.value;
uiConfig.numberSize = 18;
uiConfig.sloganOffsetY = isiOS ? 20 : 160;
uiConfig.sloganVerticalLayoutItem = JVIOSLayoutItem.ItemNumber;
uiConfig.sloganTextColor = Colors.black.value;
uiConfig.sloganTextSize = 15;
//uiConfig.sloganHidden = 0;
uiConfig.logBtnWidth = 220;
uiConfig.logBtnHeight = 50;
//uiConfig.logBtnOffsetX = isiOS ? 0 : null;//(screenWidth/2 - uiConfig.logBtnWidth/2).toInt();
uiConfig.logBtnOffsetY = isiOS ? 20 : 230;
uiConfig.logBtnVerticalLayoutItem = JVIOSLayoutItem.ItemSlogan;
uiConfig.logBtnText = "登陸按鈕";
uiConfig.logBtnTextColor = Colors.brown.value;
uiConfig.logBtnTextSize = 16;
uiConfig.loginBtnNormalImage = "login_btn_normal";//圖片必須存在
uiConfig.loginBtnPressedImage = "login_btn_press";//圖片必須存在
uiConfig.loginBtnUnableImage = "login_btn_unable";//圖片必須存在
uiConfig.privacyState = true;//設置默認勾選
uiConfig.privacyCheckboxSize = 20;
uiConfig.checkedImgPath = "check_image";//圖片必須存在
uiConfig.uncheckedImgPath = "uncheck_image";//圖片必須存在
uiConfig.privacyCheckboxInCenter = true;
//uiConfig.privacyCheckboxHidden = false;
//uiConfig.privacyOffsetX = isiOS ? (20 + uiConfig.privacyCheckboxSize) : null;
uiConfig.privacyOffsetY = 15;// 距離底部距離
uiConfig.privacyVerticalLayoutItem = JVIOSLayoutItem.ItemSuper;
uiConfig.clauseName = "協議1";
uiConfig.clauseUrl = "http://www.baidu.com";
uiConfig.clauseBaseColor = Colors.black.value;
uiConfig.clauseNameTwo = "協議二";
uiConfig.clauseUrlTwo = "http://www.hao123.com";
uiConfig.clauseColor = Colors.red.value;
uiConfig.privacyText = ["1極","2光","3認","4證"];
uiConfig.privacyTextSize = 13;
//uiConfig.privacyWithBookTitleMark = true;
//uiConfig.privacyTextCenterGravity = false;
uiConfig.privacyNavColor = Colors.red.value;;
uiConfig.privacyNavTitleTextColor = Colors.blue.value;
uiConfig.privacyNavTitleTextSize = 16;
uiConfig.privacyNavTitleTitle1 = "協議1 web頁標題";
uiConfig.privacyNavTitleTitle2 = "協議2 web頁標題";
uiConfig.privacyNavReturnBtnImage = "return_bg";//圖片必須存在;
複製代碼
這裏就再也不對每一個參數進行說明了,很好理解。
好了接下來就是咱們客戶端的最後一步了,調起一鍵登陸界面和邏輯。
這裏提供了兩種方法:同步和異步,就看自身業務邏輯須要了。
/// 方式一:使用同步接口 (若是想使用異步接口,則忽略此步驟,看方式二)
/// 先,添加 loginAuthSyncApi 接口回調的監聽
jverify.addLoginAuthCallBackListener((event){
setState(() {
_loading = false;
_result = "監聽獲取返回數據:[${event.code}] message = ${event.message}";
});
print("經過添加監聽,獲取到 loginAuthSyncApi 接口返回數據,code=${event.code},message = ${event.message},operator = ${event.operator}");
});
/// 再,執行同步的一鍵登陸接口
jverify.loginAuthSyncApi(autoDismiss: true);
/// 方式二:使用異步接口 (若是想使用異步接口,則忽略此步驟,看方式二)
/// 先,執行異步的一鍵登陸接口
jverify.loginAuth(true).then((map) {
/// 再,在回調裏獲取 loginAuth 接口異步返回數據(若是是經過添加 JVLoginAuthCallBackListener 監聽來獲取返回數據,則忽略此步驟)
int code = map[f_code_key];
String content = map[f_msg_key];
String operator = map[f_opr_key];
setState(() {
_loading = false;
_result = "接口異步返回數據:[$code] message = $content";
});
print("經過接口異步返回,獲取到 loginAuth 接口返回數據,code=$code,message = $content,operator = $operator");
});
複製代碼
到此,基本完成客戶端代碼工做了,咱們執行下看看效果:
「coding01一鍵登陸」:
若是返回碼爲:6000,則 message 的值就是咱們須要的 loginToken。
下面咱們開始後臺的接口對接工做了,咱們能夠將 loginToken 傳給咱們本身的服務器接口,而後再利用極光提供的REST API 提供的 loginTokenVerify API
獲取加密的手機號數據,註冊或者登陸操做,下發給客戶端建立用戶或者登陸成功後的 Auth 認證信息。
功能說明:提交loginToken,驗證後返回手機號碼
調用接口:POST api.verification.jpush.cn/v1/web/logi…
我主要仍是基於 Laravel PHP 框架來使用 loginTokenVerify API,這裏使用的是 GuzzleHttp
網絡請求插件:
/* * 經過客戶端提供的 loginToken,請求極光接口得到加密手機號 */
public function jiguanVerify($loginToken) {
$client = new Client(['base_uri' => $this->loginTokenVerifyUrl]);
try {
$response = $client->request('POST', '', [
'json' => [
'loginToken' => $loginToken
],
'auth' => [env('JPUSH_APPKEY'), env('JPUSH_MASTERSECRET')],
]);
$contents = json_decode($response->getBody()->getContents(), true);
// 正確結果
// {"id":117270465679982592,"code":8000,"content":"get phone success","exID":"1234566","phone":"HpBLIQ/6SkFl0pAq0LMdw1aZ8RHoofgWmaY//LE+0ahkSdHC5oTCnjrR8Tj8y5naKVI03torFU+EzAQnwtVqAoQyYckT0S3Q02TKuAal3VRGiR5Lmp4g2A5Mh4/W5A4o6QFviHuBVJZE/WV0AzU5w4NGhpyQntOeF0UyovYATy4="}
// 失敗結果
// {"id":268773997490073600,"code":8001,"content":"get phone fail","exID":null,"phone":null}
if ( $contents['code'] == 8000) {
return [
'verify' => true,
'message' => $this->getPhone($contents['phone']) // 解碼獲取手機號
];
}
return [
'verify' => false,
'message' => $contents['content']
];
} catch (RequestException $e) {
return [
'verify' => false,
'message' => $e->getMessage()
];
} catch (GuzzleException $e) {
return [
'verify' => false,
'message' => $e->getMessage()
];
}
}
複製代碼
固然根據官網說明,經過 loginTokenVerify API 接口返回的手機號是加密的,須要進行解密,一開始申請認證時,咱們在極光後臺配置了咱們的「RSA 加密公鑰」,這時候就派上用場了。
具體看方法 $this->getPhone($contents['phone'])
:
/** * @param $phone * @return string 解密的手機號 */
private function getPhone($phone) {
$prefix = '-----BEGIN RSA PRIVATE KEY-----';
$suffix = '-----END RSA PRIVATE KEY-----';
$result = '';
$encrypted = null;
$prikey = null;
$key = $prefix . "\n" . $prikey . "\n" . $suffix;
openssl_private_decrypt(base64_decode($encrypted), $result, openssl_pkey_get_private($key));
return $result . "\n";
}
複製代碼
拿到手機號後,那剩下的就是和咱們業務流程有關的代碼了,利用手機號登陸用戶信息,或者建立用戶,而後下發登陸成功的 Auth 信息給咱們的客戶端。
有了極光認證提供的一鍵登陸功能,咱們客戶端開發就變得很簡單,再也不須要用戶本身手動輸入手機號,客戶端和接口端去驗證手機號的有效性、下發驗證碼到第三方短信平臺、再由短信平臺下發給用戶,用戶再去客戶端去輸入驗證碼,而後驗證成功,再把信息提交給接口,接口拿着手機號去作認證操做。
全部的操做都不須要了,用戶只需點一點「本地手機號一鍵登陸」便可,剩下的都交給咱們開發來完成,並且咱們開發工做量也變得不多,只須要一個請求接口就可完成登陸功能
這就是極光認證功能 —— 一鍵登陸的做用。
推薦一款 Flutter Push 推送功能插件,這是使用極光推送的 Flutter 插件,能夠簡化推送功能開發,推送一步到位,推薦閱讀:mp.weixin.qq.com/s/l0_lghnp7…
跟我一步一步實現 Flutter 視頻播放插件,這是一篇早期 Flutter 剛在國內使用時,針對視頻播放器 SDK 製做的 Flutter 插件,後來有些大廠工程師們也參考這篇文章去使用和開發插件,強烈推薦一看:mp.weixin.qq.com/s/goMXcCpcq…
JPush's officially supported Flutter plugin (Android & iOS). 極光推送官方支持的 Flutter 插件(Android & iOS)。而本文的 demo 代碼主要來自此,推薦查看源代碼,是學習的最好途徑。github.com/jpush/jveri…
下一步咱們來解讀 Flutter 插件源碼,未完待續