Android开发:微信登录功能实现

1.应用申请

应用申请详情步骤

2.添加依赖

2.1 build.grade文件

  1. 首先将android项目一级目录下的build.grade中的ext.kotlin_version修改为1.4.10

    // 将ext.kotlin_version 修改为1.4.10
    buildscript {
        ext.kotlin_version = '1.4.10'
    }
    

    Android开发:微信登录功能实现_第1张图片

  2. 然后在android项目二级目录app下的build.grade文件中添加如下依赖:

    // 在dependencies中加入api依赖
    dependencies {
    		api 'com.tencent.mm.ensdk:wechat-sdk-android-without-mta:+'
    }
    

    Android开发:微信登录功能实现_第2张图片

2.2 pubspec.yaml文件

  1. 在android项目一级目录下的pubspec.yaml文件中添加相应的fluwx版本
    // 加入fluwx版本依赖
    fluwx: ^3.5.1
    
  2. Android开发:微信登录功能实现_第3张图片

3.具体实现

3.1 创建文件

在lib目录下的services目录下创建weixin_service.dart文件

Android开发:微信登录功能实现_第4张图片

3.2 导入fluwx相关包

导入fluwx需要的相关文件fluwx.dart,并重命名为fluwx

import 'package:fluwx/fluwx.dart' as fluwx;

3.3 注册微信SDK服务

通过fluwx.dart文件中的registerWxApi方法注册微信SDK服务

await fluwx.registerWxApi(
      appId: 'wxe99231e0b8e08dcf',
    );

参数说明

3.4 判断是否安装微信

判断是否安装微信程序,一般在IOS开发使用,android开发为非必选项

/// 如果安装微信程序,则继续下一步骤,否则直接返回错误信息
bool hasWeChat = await fluwx.isWeChatInstalled;
if (hasWeChat) {
	...
}else{
	处理错误;
}

3.5 微信授权

微信授权是环节中最重要的一步,只有经过微信授权,才具备获取code的权限,才能正常执行后续步骤,**由于授权操作安全等级较高,所以在发起授权请求时,微信会对授权链接做正则强匹配校验,如果链接的参数顺序不对,授权页面将无法正常访问。**若用户同意授权,则页面将跳转至 redirect_uri/?code=CODE&state=STATE。

/// 微信授权操作
await fluwx.sendWeChatAuth(
          scope: 'snsapi_userinfo', state: 'wechat_sdk_demo');

参数说明

3.6 code获取

确保微信公众账号拥有授权作用域(scope参数)的权限的前提下(服务号获得高级接口后,默认拥有scope参数中的snsapi_base和snsapi_userinfo),才能获取code。并且code作为换取access_token的票据,每次用户授权带上的code将不一样,code只能使用一次,5分钟未被使用自动过期。

注:由于公众号的secret和获取到的access_token安全级别都非常高,必须只保存在服务器,不允许传给客户端。后续刷新access_token、通过access_token获取用户信息等步骤,也必须从服务器发起。

fluwx.weChatResponseEventHandler
          .distinct((fluwx.BaseWeChatResponse a, fluwx.BaseWeChatResponse b) =>
              a == b)
          .listen((fluwx.BaseWeChatResponse event) async {
        if (event is fluwx.WeChatAuthResponse) {
          _code = event.code;
				}else{
					获取code失败,请检查参数是否填写错误,是否拥有scope参数对应的授权作用域权限
				}

返回值说明

3.7 access_token获取

acces_token将获取的code作为兑换票据,将其作为HTTP请求的参数,向请求网址发送HTTP请求来获取access_token。

  1. 请求说明

    /// Http().get()为封装好的函数
    final dynamic res = await Http().get(
                  '',
                  data: {
                    'appid': 'wxe99231e0b8e08dcf',
                    'secret': '24bbdb8807d55e3c7aafb5bcd5ab62df',
                    'code': _code,
                    'grant_type': 'authorization_code'
                  });
    

    请求网址

    /// GET方式
    
    

    参数说明

  2. 返回说明

    1. 正确返回

      {
        "access_token": "ACCESS_TOKEN",
        "expires_in": 7200,
        "refresh_token": "REFRESH_TOKEN",
        "openid": "OPENID",
        "scope": "SCOPE",
        "unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
      }
      

      返回说明

    2. 错误返回

      {
        "errcode": 40029,
        "errmsg": "invalid code"
      }
      

      返回说明

3.8 将access_token解码为Json格式

通过code兑换的access_token为String类型,需要将其转换成Json格式,便于操作和管理,String转换成Json的步骤如下:

  1. 将access_token包含的字段(即3.7中返回说明中正确返回和错误返回字段)放入转换网页中

  2. 检查字段是否符合格式要求

  3. 修改函数名称

  4. 检查字段类型是否正确

  5. 根据逻辑,判断字段能否为空

    Android开发:微信登录功能实现_第5张图片
  6. 上述内容检查完毕,点击生成,自动生成需要的代码

    Android开发:微信登录功能实现_第6张图片
  7. 在lib/models目录下创建wx_result_model.dart文件,将生成的代码粘贴进来

    Android开发:微信登录功能实现_第7张图片
  8. 将获取到的access_token通过如下代码进行格式转换:

    /// res即获取到的String类型的access_token
    final WxAccessTokenResultModel wxAccessTokenResultModel =
                  WxAccessTokenResultModel.fromJson(
                      json.decode(res as String) as Map)
    

3.9 用户信息获取

用户信息的获取将转换格式中的access_token作为兑换票据,将其作为请求参数向请求网址发送HTTP请求来获取用户信息。

  1. 请求说明

    /// 通过HTTP请求获取用户信息
    final dynamic userInfoResult = await Http().get(
                  '',
                  data: {
                    'access_token': wxAccessTokenResultModel.accessToken,
                    'openid': 'wxe99231e0b8e08dcf',
                    'lang': 'zh_CN'
                  });
    

    请求网址

    /// GET方式
    
    

    参数说明

  2. 返回说明

    1. 正确返回

      {
        "openid": "OPENID",
        "nickname": "NICKNAME",
        "sex": 1,
        "province": "PROVINCE",
        "city": "CITY",
        "country": "COUNTRY",
        "headimgurl": "",
        "privilege": ["PRIVILEGE1", "PRIVILEGE2"],
        "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL"
      }
      
    2. 错误返回

      {
        "errcode": 40003,
        "errmsg": "invalid openid"
      }
      

    返回说明

    注:开发者最好保存 unionID 信息,以便以后在不同应用之间进行用户信息互通。

3.10 将用户信息解码成Json格式

3.9中获取得到的用户信息仍然是String类型,需要将其解码成Json格式,便于以后的管理和调用,具体转换方式类似3.8,将用户信息中的字段通过网页转成Json格式,自动生成代码,在lib/models下创建wx_user_info_result.dart文件并粘贴代码,封装完成后,通过weixin_services.dart文件调用,具体调用代码如下:

/// 通过封装类WxUserInfoResult将返回的String类型用户信息转成Json格式
final WxUserInfoResult wxUserInfoResult = WxUserInfoResult.fromJson(
              json.decode(userInfoResult as String) as Map);

4.具体代码

4.1 weixin_service.dart

@override
  Future onInit() async {
    ///1.是否成功注册微信sdk,registerWxApi方法,其中appId为申请微信应用的Id
    isBindWxSdk.value = await fluwx.registerWxApi(
      appId: 'wxe99231e0b8e08dcf',
      doOnAndroid: true,
    );

    ///2.是否安装微信,isWeChatInstalled方法,若未安装则返回错误信息
    bool hasWeChat = await fluwx.isWeChatInstalled;
    if (hasWeChat) {
		///3.微信授权
      checkWxLogin.value = await fluwx.sendWeChatAuth(
          scope: 'snsapi_userinfo', state: 'wechat_sdk_demo');

      ///4.获取code,weChatResponseEventHandler方法
      fluwx.weChatResponseEventHandler
          .distinct((fluwx.BaseWeChatResponse a, fluwx.BaseWeChatResponse b) =>
              a == b)
          .listen((fluwx.BaseWeChatResponse event) async {
        if (event is fluwx.WeChatAuthResponse) {

          _code = event.code;

          ///5.获取accessToken,通过HTTP请求获得
					//get方法中的参数为url和data,url为请求数据的网址,data则为请求数据时必须的字段
          final dynamic res = await Http().get(
              '',
              data: {
                'appid': 'wxe99231e0b8e08dcf',
                'secret': '24bbdb8807d55e3c7aafb5bcd5ab62df',
                'code': _code,
                'grant_type': 'authorization_code'
              });
					///封装类,通过该类才能把获取到的字符串数据转成Json格式的数据
          final WxAccessTokenResultModel wxAccessTokenResultModel =
              WxAccessTokenResultModel.fromJson(
                  json.decode(res as String) as Map);
      

          //6.获取用户信息,同上述步骤
          final dynamic userInfoResult = await Http().get(
              '',
              data: {
                'access_token': wxAccessTokenResultModel.accessToken,
                'openid': 'wxe99231e0b8e08dcf',
                'lang': 'zh_CN'
              });
          final WxUserInfoResult wxUserInfoResult = WxUserInfoResult.fromJson(
              json.decode(userInfoResult as String) as Map);
        }
      });
      // 获取access token

    } else {
      print('该手机未安装微信程序');
    }

    super.onInit();
  }

4.2 wx_result_model.dart

import 'dart:convert';

T? asT(dynamic value) {
  if (value is T) {
    return value;
  }
  return null;
}

class WxAccessTokenResultModel {
  WxAccessTokenResultModel({
    this.accessToken,
    this.expiresIn,
    this.refreshToken,
    this.openid,
    this.scope,
    this.unionid,
    this.errcode,
    this.errmsg,
  });

  factory WxAccessTokenResultModel.fromJson(Map jsonRes) =>
      WxAccessTokenResultModel(
        accessToken: asT(jsonRes['access_token']),
        expiresIn: asT(jsonRes['expires_in']),
        refreshToken: asT(jsonRes['refresh_token']),
        openid: asT(jsonRes['openid']),
        scope: asT(jsonRes['scope']),
        unionid: asT(jsonRes['unionid']),
        errcode: asT(jsonRes['errcode']),
        errmsg: asT(jsonRes['errmsg']),
      );

  final String? accessToken;
  final int? expiresIn;
  final String? refreshToken;
  final String? openid;
  final String? scope;
  final String? unionid;
  final int? errcode;
  final String? errmsg;

  @override
  String toString() {
    return jsonEncode(this);
  }

  Map toJson() => {
        'access_token': accessToken,
        'expires_in': expiresIn,
        'refresh_token': refreshToken,
        'openid': openid,
        'scope': scope,
        'unionid': unionid,
        'errcode': errcode,
        'errmsg': errmsg,
      };

  WxAccessTokenResultModel clone() => WxAccessTokenResultModel.fromJson(
      asT>(jsonDecode(jsonEncode(this)))!);
}

4.3 wx_user_info_result.dart

import 'dart:convert';

T? asT(dynamic value) {
  if (value is T) {
    return value;
  }
  return null;
}

class WxUserInfoResult {
  WxUserInfoResult({
    this.openid,
    this.nickname,
    this.sex,
    this.province,
    this.city,
    this.country,
    this.headimgurl,
    this.privilege,
    this.unionid,
    this.errcode,
    this.errmsg,
  });

  factory WxUserInfoResult.fromJson(Map jsonRes) {
    final List? privilege =
        jsonRes['privilege'] is List ? [] : null;
    if (privilege != null) {
      for (final dynamic item in jsonRes['privilege']!) {
        if (item != null) {
          privilege.add(asT(item)!);
        }
      }
    }
    return WxUserInfoResult(
      openid: asT(jsonRes['openid']),
      nickname: asT(jsonRes['nickname']),
      sex: asT(jsonRes['sex']),
      province: asT(jsonRes['province']),
      city: asT(jsonRes['city']),
      country: asT(jsonRes['country']),
      headimgurl: asT(jsonRes['headimgurl']),
      privilege: privilege,
      unionid: asT(jsonRes['unionid']),
      errcode: asT(jsonRes['errcode']),
      errmsg: asT(jsonRes['errmsg']),
    );
  }

  final String? openid;
  final String? nickname;
  final int? sex;
  final String? province;
  final String? city;
  final String? country;
  final String? headimgurl;
  final List? privilege;
  final String? unionid;
  final int? errcode;
  final String? errmsg;

  @override
  String toString() {
    return jsonEncode(this);
  }

  Map toJson() => {
        'openid': openid,
        'nickname': nickname,
        'sex': sex,
        'province': province,
        'city': city,
        'country': country,
        'headimgurl': headimgurl,
        'privilege': privilege,
        'unionid': unionid,
        'errcode': errcode,
        'errmsg': errmsg,
      };

  WxUserInfoResult clone() => WxUserInfoResult.fromJson(
      asT>(jsonDecode(jsonEncode(this)))!);
}

你可能感兴趣的:(Android开发,android)