1.应用申请
2.添加依赖
2.1 build.grade文件
首先将android项目一级目录下的build.grade中的ext.kotlin_version修改为1.4.10
// 将ext.kotlin_version 修改为1.4.10 buildscript { ext.kotlin_version = '1.4.10' }
然后在android项目二级目录app下的build.grade文件中添加如下依赖:
// 在dependencies中加入api依赖 dependencies { api 'com.tencent.mm.ensdk:wechat-sdk-android-without-mta:+' }
2.2 pubspec.yaml文件
- 在android项目一级目录下的pubspec.yaml文件中添加相应的fluwx版本
// 加入fluwx版本依赖 fluwx: ^3.5.1 
3.具体实现
3.1 创建文件
在lib目录下的services目录下创建weixin_service.dart文件

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。
请求说明
/// Http().get()为封装好的函数 final dynamic res = await Http().get( '<https://api.weixin.qq.com/sns/oauth2/access_token>', data: <String, dynamic>{ 'appid': 'wxe99231e0b8e08dcf', 'secret': '24bbdb8807d55e3c7aafb5bcd5ab62df', 'code': _code, 'grant_type': 'authorization_code' });请求网址
/// GET方式 <https://api.weixin.qq.com/sns/oauth2/access_token>返回说明
3.8 将access_token解码为Json格式
通过code兑换的access_token为String类型,需要将其转换成Json格式,便于操作和管理,String转换成Json的步骤如下:
将access_token包含的字段(即3.7中返回说明中正确返回和错误返回字段)放入转换网页中
检查字段是否符合格式要求
修改函数名称
检查字段类型是否正确
根据逻辑,判断字段能否为空

上述内容检查完毕,点击生成,自动生成需要的代码

在lib/models目录下创建wx_result_model.dart文件,将生成的代码粘贴进来

将获取到的access_token通过如下代码进行格式转换:
/// res即获取到的String类型的access_token final WxAccessTokenResultModel wxAccessTokenResultModel = WxAccessTokenResultModel.fromJson( json.decode(res as String) as Map<String, dynamic>)
3.9 用户信息获取
用户信息的获取将转换格式中的access_token作为兑换票据,将其作为请求参数向请求网址发送HTTP请求来获取用户信息。
请求说明
/// 通过HTTP请求获取用户信息 final dynamic userInfoResult = await Http().get( '<https://api.weixin.qq.com/sns/userinfo>', data: <String, dynamic>{ 'access_token': wxAccessTokenResultModel.accessToken, 'openid': 'wxe99231e0b8e08dcf', 'lang': 'zh_CN' });请求网址
/// GET方式 <https://api.weixin.qq.com/sns/userinfo>返回说明
正确返回
{ "openid": "OPENID", "nickname": "NICKNAME", "sex": 1, "province": "PROVINCE", "city": "CITY", "country": "COUNTRY", "headimgurl": "<https://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0>", "privilege": ["PRIVILEGE1", "PRIVILEGE2"], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" }错误返回
{ "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<String, dynamic>);
4.具体代码
4.1 weixin_service.dart
@override
Future<void> 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(
'<https://api.weixin.qq.com/sns/oauth2/access_token>',
data: <String, dynamic>{
'appid': 'wxe99231e0b8e08dcf',
'secret': '24bbdb8807d55e3c7aafb5bcd5ab62df',
'code': _code,
'grant_type': 'authorization_code'
});
///封装类,通过该类才能把获取到的字符串数据转成Json格式的数据
final WxAccessTokenResultModel wxAccessTokenResultModel =
WxAccessTokenResultModel.fromJson(
json.decode(res as String) as Map<String, dynamic>);
//6.获取用户信息,同上述步骤
final dynamic userInfoResult = await Http().get(
'<https://api.weixin.qq.com/sns/userinfo>',
data: <String, dynamic>{
'access_token': wxAccessTokenResultModel.accessToken,
'openid': 'wxe99231e0b8e08dcf',
'lang': 'zh_CN'
});
final WxUserInfoResult wxUserInfoResult = WxUserInfoResult.fromJson(
json.decode(userInfoResult as String) as Map<String, dynamic>);
}
});
// 获取access token
} else {
print('该手机未安装微信程序');
}
super.onInit();
}
4.2 wx_result_model.dart
import 'dart:convert';
T? asT<T>(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<String, dynamic> jsonRes) =>
WxAccessTokenResultModel(
accessToken: asT<String?>(jsonRes['access_token']),
expiresIn: asT<int?>(jsonRes['expires_in']),
refreshToken: asT<String?>(jsonRes['refresh_token']),
openid: asT<String?>(jsonRes['openid']),
scope: asT<String?>(jsonRes['scope']),
unionid: asT<String?>(jsonRes['unionid']),
errcode: asT<int?>(jsonRes['errcode']),
errmsg: asT<String?>(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<String, dynamic> toJson() => <String, dynamic>{
'access_token': accessToken,
'expires_in': expiresIn,
'refresh_token': refreshToken,
'openid': openid,
'scope': scope,
'unionid': unionid,
'errcode': errcode,
'errmsg': errmsg,
};
WxAccessTokenResultModel clone() => WxAccessTokenResultModel.fromJson(
asT<Map<String, dynamic>>(jsonDecode(jsonEncode(this)))!);
}
4.3 wx_user_info_result.dart
import 'dart:convert';
T? asT<T>(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<String, dynamic> jsonRes) {
final List<String>? privilege =
jsonRes['privilege'] is List ? <String>[] : null;
if (privilege != null) {
for (final dynamic item in jsonRes['privilege']!) {
if (item != null) {
privilege.add(asT<String>(item)!);
}
}
}
return WxUserInfoResult(
openid: asT<String?>(jsonRes['openid']),
nickname: asT<String?>(jsonRes['nickname']),
sex: asT<int?>(jsonRes['sex']),
province: asT<String?>(jsonRes['province']),
city: asT<String?>(jsonRes['city']),
country: asT<String?>(jsonRes['country']),
headimgurl: asT<String?>(jsonRes['headimgurl']),
privilege: privilege,
unionid: asT<String?>(jsonRes['unionid']),
errcode: asT<int?>(jsonRes['errcode']),
errmsg: asT<String?>(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<String>? privilege;
final String? unionid;
final int? errcode;
final String? errmsg;
@override
String toString() {
return jsonEncode(this);
}
Map<String, dynamic> toJson() => <String, dynamic>{
'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<Map<String, dynamic>>(jsonDecode(jsonEncode(this)))!);
}