Flutter學習第十五天:2021年最新版超詳細Flutter2.0實現Mob+SMSSDK手機驗證碼登入實現,Android和Flutter混合開發?

android小白星發表於2021-04-01

關於這個功能實現的靈感來自於Flutter實現百度語音轉文字功能這篇部落格,以為我以前出過一篇android怎麼實現手機號登入的部落格,這篇部落格主要是針對Android端的實現,所以我們可以通過flutter和Android實現相互通訊,從而達到flutter也可以實現手機驗證碼登入的效果在這裡插入圖片描述 廢話少說,我們先看一下效果,因為個人隱私問題,我把手機號碼設定為了密碼型別,但是不影響效果: 在這裡插入圖片描述

雖然白嫖固然好,但是首先宣告一下,因為這個平臺的每個賬號,一天只能傳送10次驗證碼。 所以我建議你自己去註冊這個平臺,建立一個賬號來獲取驗證碼登入功能的App Key和App Secret。關於如何註冊這個平臺應用,你可以去看一下我的Android實現手機驗證碼登入這篇部落格,說的挺詳細的,大概從開始看到下圖紅色圓圈處就可以了。 在這裡插入圖片描述

第一步:在mob平臺配置SMSSDK環境

==因為下面那篇部落格已經說的很清楚了,所以我就不在做詳細說明==。 關於如何註冊這個平臺應用,你可以去看一下我的Android實現手機驗證碼登入blog.csdn.net/qq_45137584… 這篇部落格,說的挺詳細的,大概從開始看到下圖紅色圓圈處就可以了。 在這裡插入圖片描述

第二步:建立flutter專案和android的library檔案

關於這個步驟因為我以前的部落格有說過,就不在進行說明了,可以看一下我的Flutter實現百度語音轉文字功能,從開頭看到下圖紅色圓圈處部分就可以了。 在這裡插入圖片描述 記得仔細閱讀每一步,如果你缺少了一步,可以就會導致你的功能無法實現。

下面的文字是補充,可以不需要看。 看一下我們建立的專案結構吧,關於Android端那裡爆紅是因為我這個是flutter的專案,沒有Android端相關的jar檔案,只需要我們把那個爆紅的檔案,用Android studio開啟即可。 在這裡插入圖片描述

在這裡插入圖片描述 下面就我們通過Android studio開啟的檔案,然後我們在他裡面建立的Android的library的檔案,名字是mob_plugin。 在這裡插入圖片描述

第三步:在Android的library檔案中部署mob+SMSSDK環境

1.在project的build.gradle檔案中加入如下程式碼

在這裡插入圖片描述 程式碼如下:

classpath "com.mob.sdk:MobSDK:2018.0319.1724"
複製程式碼
maven { url 'https://jitpack.io' }
複製程式碼

2.在你建立的library中加入如下程式碼

在這裡插入圖片描述 在這裡插入圖片描述

在這裡插入圖片描述 程式碼如下: 配置mob環境的程式碼

id 'com.mob.sdk'
複製程式碼

建議修改為自己的appKey和appSecret

MobSDK {
    appKey "31d18b327d099"     //修改為你自己的appKey
    appSecret "5e6a2e16f58f9c1e374acf77abb70b70" //修改為你自己的appSecret
    SMSSDK {}
}
複製程式碼

配置flutter的環境:因為我在與flutter端通訊的時候需要用到flutter的庫,所以需要配置flutter的環境。

程式碼如下:

def localProperties = new Properties()
def localPropertiesFile = rootProject.file('local.properties')
if (localPropertiesFile.exists()) {
    localPropertiesFile.withReader('UTF-8') { reader ->
        localProperties.load(reader)
    }
}

def flutterRoot = localProperties.getProperty('flutter.sdk')

apply from: "$flutterRoot/packages/flutter_tools/gradle/flutter.gradle"
複製程式碼
flutter {
    source '../..'
}
複製程式碼

3.在你的AndroidMainfest.xml檔案中加入許可權

在這裡插入圖片描述

程式碼如下:

 <uses-permission android:name="android.permission.READ_CONTACTS" />
    <uses-permission android:name="android.permission.READ_PHONE_STATE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />
    <uses-permission android:name="android.permission.GET_TASKS" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
複製程式碼

第四步:在flutter的Android檔案中配置環境

1.修改版本

==首先把build.gradle(Module:app)檔案中圖中紅色圓圈處改為與build.gradle(Module:mob_plugin)檔案中版本相同== 在這裡插入圖片描述

2.flutter的Android檔案中匯入android端的library和配置mob環境

配置mob環境: 在這裡插入圖片描述 程式碼如下: 配置mob環境

apply plugin: 'com.mob.sdk'
複製程式碼

匯入library庫 mob_plugin改為你自己的library庫名即可

implementation project(':mob_plugin')
複製程式碼

第五步:實現flutter驗證碼功能

1.在flutter端首先UI設計(view層)

這個頁面的實現對於學過flutter的人來說比較簡單,畢竟我們主要是用於測試功能,所以沒必要做的過於複雜。主要就兩個輸入框和兩個按鈕。 這裡我就說一下主要的一個部分吧,程式碼如下

///這個方法主要是把你輸入的手機號碼傳輸過去
ArsManager.telephone(myController.text);

///這個方法主要是把你輸入的手機號碼和驗證碼存入Map裡面,然後傳輸過去。
Map ages={};
      ages['phone']=myController.text;
      ages['code']=myController1.text;
      ArsManager.correct(ages).then((result){
        int code = result["code"];
        String message = result["message"];
        if(message=="提交驗證碼正確") {
          Navigator.of(context).push( MaterialPageRoute(builder: (context)=>Login()));
        }else{
            print(message);
        }
      });
複製程式碼

main.dart頁面

import 'package:flutter/material.dart';
import 'package:mob_app/asr_manger.dart';
import 'package:mob_app/login.dart';

void main() {
  runApp(MaterialApp(
    home: MyApp(),
  ));
}

class MyApp extends StatefulWidget {
  @override
  _MyAppState createState() => _MyAppState();
}

class _MyAppState extends State<MyApp> {
  final myController = TextEditingController();
  final myController1=TextEditingController();

  @override
  void dispose() {
    // TODO: implement dispose
    myController.dispose();
    super.dispose();
  }
  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: Column(
        children: [
          Padding(
            padding: const EdgeInsets.all(8.0),
            child: TextField(
              controller: myController,
              obscureText: true,
              decoration: InputDecoration(
                  labelText: "請輸入手機號碼",
                  hintText: "請輸入手機號碼",
                  prefixIcon: Icon(Icons.people_alt_rounded)),
            ),
          ),
          Container(
            height: 40,
            child:OutlineButton(
              borderSide:new BorderSide(color: Theme.of(context).primaryColor),
              child: new Text('獲取驗證碼',style: new TextStyle(color: Theme.of(context).primaryColor),),
              onPressed: (){
                _data();
              },
            ),
          ),
          Padding(
            padding: const EdgeInsets.all(4.0),
            child: TextField(
              controller: myController1,
              decoration: InputDecoration(
                labelText: "請輸入驗證碼",
                prefixIcon: Icon(Icons.lock),
                hintText: "請輸入驗證碼",
              ),
            ),
          ),
          Container(
            height: 40,
            child:OutlineButton(
              borderSide:new BorderSide(color: Theme.of(context).primaryColor),
              child: new Text('登入',style: new TextStyle(color: Theme.of(context).primaryColor),),
              onPressed: (){
                _login();
              },
            ),
          ),
        ],
      ),
    );
  }

  _data() {
    setState(() {
      ArsManager.telephone(myController.text);
    });
  }

  _login() {
    setState(() {
      Map ages={};
      ages['phone']=myController.text;
      ages['code']=myController1.text;
      ArsManager.correct(ages).then((result){
        int code = result["code"];
        String message = result["message"];
        if(message=="提交驗證碼正確") {
          Navigator.of(context).push( MaterialPageRoute(builder: (context)=>Login()));
        }else{
            print(message);
        }
      });
    });
  }
}

複製程式碼

這個頁面用於我們驗證碼驗證成功的時候跳轉頁面。 login.dart頁面:

import 'package:flutter/material.dart';

class Login extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return Center(
      child: Text('登入成功',style: TextStyle(decoration: TextDecoration.none,fontSize: 20,color:Color(0xFFFFFFFF)),),
    );
  }
}

複製程式碼

2.配置flutter端的MethodChannel

這裡我們主要設定了兩個方法: telephone方法:把手機號碼傳輸給Android端,然後傳送驗證碼的方法。 傳送的值是String型別,返回的值也是String型別 correct方法:把手機號碼和你輸入的驗證碼傳輸給Android端,然後實現驗證驗證碼輸入是否正確。 傳送的值是Map型別,返回的值是dynamic型別 如果對於那個基礎型別不是很懂,可以去看一下我的這篇文章dart的基礎型別

程式碼如下:

import 'dart:async';
import 'package:flutter/services.dart';

class ArsManager{
  static const MethodChannel _channel=const MethodChannel('asr_plugin');

  static Future<String> telephone(String phone) async{
    return await _channel.invokeMethod('telephone',phone);
  }

  static Future<dynamic> correct(Map map) async{
    return await _channel.invokeMethod('correct',map);
  }
}
複製程式碼

3.在Android端配置實現傳送驗證碼和驗證驗證碼需要的方法

主要使用到三個方法: send方法:輸入值是phone;主要功能就是通過手機號碼獲取驗證碼 submit方法:主要輸入值是phone,code;主要功能就是通過手機號碼和輸入的驗證碼來驗證驗證碼是否輸入正確。 verification方法:主要輸入值是message;主要功能就是回撥驗證碼的輸入是否正確,然後把結果傳送給flutter端

package com.example.mob_plugin;

import android.app.Activity;
import android.text.TextUtils;
import android.util.Log;
import com.mob.MobSDK;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.HashMap;
import java.util.Map;

import cn.smssdk.EventHandler;
import cn.smssdk.SMSSDK;
import io.flutter.plugin.common.MethodChannel;

class ArsManger extends Activity {
    EventHandler handler;
    boolean f1=false;
    
    public void submit(String phone, String code, Activity activity, MethodChannel.Result result) {
        SMSSDK.submitVerificationCode("86",phone,code);
        verification(activity,result);
    }

    //點選傳送驗證碼
    public void send(String phone) {
        //獲取驗證碼
        SMSSDK.getVerificationCode("86",phone);
    }

    public void verification(Activity activity,MethodChannel.Result message){
        MobSDK.init(activity, "31d18b327d099","5e6a2e16f58f9c1e374acf77abb70b70");
        handler = new EventHandler(){
            @Override
            public void afterEvent(int event, int result, Object data) {
                if (result == SMSSDK.RESULT_COMPLETE){
                    //回撥完成
                    if (event == SMSSDK.EVENT_SUBMIT_VERIFICATION_CODE) {
                        //提交驗證碼成功
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                Log.e("123","提交驗證碼正確");
                                Map<String, Object> resultMap = new HashMap<>();
                                resultMap.put("message", "提交驗證碼正確");
                                resultMap.put("code", 200);
                                //發訊息至 Flutter
                                //此方法只能使用一次
                                message.success(resultMap);
                            }
                        });

                    }else if (event == SMSSDK.EVENT_GET_VERIFICATION_CODE){
                        //獲取驗證碼成功
                        runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                               // Toast.makeText(MainActivity.this,"驗證碼已傳送", Toast.LENGTH_SHORT).show();
                                Log.e("123","驗證碼已傳送");
                                Map<String, Object> resultMap = new HashMap<>();
                                resultMap.put("message", "驗證碼已傳送");
                                resultMap.put("code", 200);
                                //發訊息至 Flutter
                                //此方法只能使用一次
                                message.success(resultMap);
                            }
                        });
                    }else if (event == SMSSDK.EVENT_GET_SUPPORTED_COUNTRIES){
                    }
                }else{
                    ((Throwable)data).printStackTrace();
                    Throwable throwable = (Throwable) data;
                    try {
                        JSONObject obj = new JSONObject(throwable.getMessage());
                        final String des = obj.optString("detail");
                        if (!TextUtils.isEmpty(des)){
                            runOnUiThread(new Runnable() {
                                @Override
                                public void run() {
                                    Log.e("123","提交錯誤資訊");
                                   // Toast.makeText(MainActivity.this,"提交錯誤資訊", Toast.LENGTH_SHORT).show();
                                    Map<String, Object> resultMap = new HashMap<>();
                                    resultMap.put("message", "提交錯誤資訊");
                                    resultMap.put("code", 200);
                                    //發訊息至 Flutter
                                    //此方法只能使用一次
                                    message.success(resultMap);
                                }
                            });
                        }
                    } catch (JSONException e) {
                        e.printStackTrace();
                    }

                }
            }
        };

        SMSSDK.registerEventHandler(handler);
    }
}

複製程式碼

說一下上面程式碼中的一段程式碼: 程式碼如下: 主要用於把我們verification方法的回撥結果返回給flutter,這裡屬於Android傳送給flutter端的一段程式碼

 Map<String, Object> resultMap = new HashMap<>();
 resultMap.put("message", "驗證碼正確");
 resultMap.put("code", 200);
 //發訊息至 Flutter
 //此方法只能使用一次
 message.success(resultMap);
複製程式碼

4.在Android端配置MethodChannel

主要使用的兩個方法: registerWith方法:等下會用到,主要用於註冊plugin,實現通訊功能。 onMethodCall方法:這個方法是我們繼承MethodChannel.MethodCallHandler類來使用的方法,主要是功能是接受來自flutter傳送過來的資料。

package com.example.mob_plugin;

import android.app.Activity;
import androidx.annotation.NonNull;

import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

public class AsrPlugin implements MethodChannel.MethodCallHandler {
    private final Activity activity;
    ArsManger arsManger=new ArsManger();

    public static void registerWith(Activity activity, BinaryMessenger messenger) {
        MethodChannel channel = new MethodChannel(messenger, "asr_plugin");
        AsrPlugin instance = new AsrPlugin(activity);
        channel.setMethodCallHandler(instance);
    }

    public AsrPlugin(Activity activity) {
        this.activity = activity;
    }

    @Override
    public void onMethodCall(@NonNull MethodCall methodCall, @NonNull MethodChannel.Result result) {
        switch (methodCall.method) {
            case "telephone":
                arsManger.send(methodCall.arguments.toString());
                break;
            case "correct":
                arsManger.submit(methodCall.argument("phone"),methodCall.argument("code"),activity,result);
                break;
            default:
                result.notImplemented();
        }
    }
}

複製程式碼

5.最後註冊plugin,實現資料通訊

在這裡插入圖片描述 程式碼如下:

package com.example.mob_app;

import android.os.Bundle;

import androidx.annotation.NonNull;


import com.example.mob_plugin.AsrPlugin;

import io.flutter.embedding.android.FlutterActivity;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugins.GeneratedPluginRegistrant;

public class MainActivity extends FlutterActivity {
    @Override
    public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
        GeneratedPluginRegistrant.registerWith(flutterEngine);
        //flutter sdk >= v1.17.0 時使用下面方法註冊自定義plugin
        AsrPlugin.registerWith(this, flutterEngine.getDartExecutor().getBinaryMessenger());
    }

    @Override
    protected void onCreate(Bundle savedInstanceState   ) {
        super.onCreate(savedInstanceState);
    }
}

複製程式碼

過程還是比較多的,其實全部程式碼都已經寫出來,如果你覺得結構不夠明瞭,可以找我要這個demo,傳送你的電子郵箱或者私聊等方法都可以。

相關文章