分离 API/SDK

This commit is contained in:
v7lin
2021-07-21 11:09:19 +08:00
parent 68febfb33e
commit 5958f60e69
17 changed files with 156 additions and 142 deletions

View File

@ -1,5 +1,5 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:wechat_kit/src/model/api/wechat_api_resp.dart'; import 'package:wechat_kit_example/api/model/wechat_api_resp.dart';
part 'wechat_access_token_resp.g.dart'; part 'wechat_access_token_resp.g.dart';

View File

@ -1,5 +1,5 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:wechat_kit/src/model/api/wechat_api_resp.dart'; import 'package:wechat_kit_example/api/model/wechat_api_resp.dart';
part 'wechat_ticket_resp.g.dart'; part 'wechat_ticket_resp.g.dart';

View File

@ -1,5 +1,5 @@
import 'package:json_annotation/json_annotation.dart'; import 'package:json_annotation/json_annotation.dart';
import 'package:wechat_kit/src/model/api/wechat_api_resp.dart'; import 'package:wechat_kit_example/api/model/wechat_api_resp.dart';
part 'wechat_user_info_resp.g.dart'; part 'wechat_user_info_resp.g.dart';

View File

@ -0,0 +1,119 @@
import 'dart:convert';
import 'dart:io';
import 'package:wechat_kit_example/api/model/wechat_access_token_resp.dart';
import 'package:wechat_kit_example/api/model/wechat_ticket_resp.dart';
import 'package:wechat_kit_example/api/model/wechat_user_info_resp.dart';
class WechatApi {
const WechatApi._();
// --- 微信APP授权登录
/// 获取 access_tokenUnionID
static Future<WechatAccessTokenResp> getAccessTokenUnionID({
required String appId,
required String appSecret,
required String code,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appId&secret=$appSecret&code=$code&grant_type=authorization_code'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 刷新或续期 access_token 使用UnionID
static Future<WechatAccessTokenResp> refreshAccessTokenUnionID({
required String appId,
required String refreshToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=$appId&grant_type=refresh_token&refresh_token=$refreshToken'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 获取用户个人信息UnionID
static Future<WechatUserInfoResp> getUserInfoUnionID({
required String openId,
required String accessToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/userinfo?access_token=$accessToken&openid=$openId'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatUserInfoResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
// --- 微信APP扫码登录
/// 获取 access_token
static Future<WechatAccessTokenResp> getAccessToken({
required String appId,
required String appSecret,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appId&secret=$appSecret'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 用上面的函数拿到的 access_token获取 sdk_ticket
static Future<WechatTicketResp> getTicket({
required String accessToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=2'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatTicketResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
}

View File

@ -6,7 +6,13 @@ import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart'; import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:image/image.dart' as image; import 'package:image/image.dart' as image;
import 'package:path/path.dart' as path; import 'package:path/path.dart' as path;
import 'package:uuid/uuid.dart';
import 'package:wechat_kit/wechat_kit.dart'; import 'package:wechat_kit/wechat_kit.dart';
import 'package:wechat_kit_example/api/model/wechat_access_token_resp.dart';
import 'package:wechat_kit_example/api/model/wechat_api_resp.dart';
import 'package:wechat_kit_example/api/model/wechat_ticket_resp.dart';
import 'package:wechat_kit_example/api/model/wechat_user_info_resp.dart';
import 'package:wechat_kit_example/api/wechat_api.dart';
const String WECHAT_APPID = 'your wechat appId'; const String WECHAT_APPID = 'your wechat appId';
const String WECHAT_UNIVERSAL_LINK = 'your wechat universal link'; // iOS 请配置 const String WECHAT_UNIVERSAL_LINK = 'your wechat universal link'; // iOS 请配置
@ -124,7 +130,7 @@ class _HomeState extends State<Home> {
if (_authResp != null && if (_authResp != null &&
_authResp!.errorCode == WechatSdkResp.ERRORCODE_SUCCESS) { _authResp!.errorCode == WechatSdkResp.ERRORCODE_SUCCESS) {
final WechatAccessTokenResp accessTokenResp = final WechatAccessTokenResp accessTokenResp =
await Wechat.instance.getAccessTokenUnionID( await WechatApi.getAccessTokenUnionID(
appId: WECHAT_APPID, appId: WECHAT_APPID,
appSecret: WECHAT_APPSECRET, appSecret: WECHAT_APPSECRET,
code: _authResp!.code!, code: _authResp!.code!,
@ -132,7 +138,7 @@ class _HomeState extends State<Home> {
if (accessTokenResp.errcode == if (accessTokenResp.errcode ==
WechatApiResp.ERRORCODE_SUCCESS) { WechatApiResp.ERRORCODE_SUCCESS) {
final WechatUserInfoResp userInfoResp = final WechatUserInfoResp userInfoResp =
await Wechat.instance.getUserInfoUnionID( await WechatApi.getUserInfoUnionID(
openId: accessTokenResp.openid!, openId: accessTokenResp.openid!,
accessToken: accessTokenResp.accessToken!, accessToken: accessTokenResp.accessToken!,
); );
@ -305,13 +311,13 @@ class _QrauthState extends State<Qrauth> {
TextButton( TextButton(
onPressed: () async { onPressed: () async {
final WechatAccessTokenResp accessToken = final WechatAccessTokenResp accessToken =
await Wechat.instance.getAccessToken( await WechatApi.getAccessToken(
appId: WECHAT_APPID, appId: WECHAT_APPID,
appSecret: WECHAT_APPSECRET, appSecret: WECHAT_APPSECRET,
); );
print( print(
'accessToken: ${accessToken.errcode} - ${accessToken.errmsg} - ${accessToken.accessToken}'); 'accessToken: ${accessToken.errcode} - ${accessToken.errmsg} - ${accessToken.accessToken}');
final WechatTicketResp ticket = await Wechat.instance.getTicket( final WechatTicketResp ticket = await WechatApi.getTicket(
accessToken: accessToken.accessToken!, accessToken: accessToken.accessToken!,
); );
print( print(
@ -319,6 +325,7 @@ class _QrauthState extends State<Qrauth> {
await Wechat.instance.startQrauth( await Wechat.instance.startQrauth(
appId: WECHAT_APPID, appId: WECHAT_APPID,
scope: <String>[WechatScope.SNSAPI_USERINFO], scope: <String>[WechatScope.SNSAPI_USERINFO],
noncestr: const Uuid().v1().toString().replaceAll('-', ''),
ticket: ticket.ticket!, ticket: ticket.ticket!,
); );
}, },

View File

@ -51,14 +51,14 @@ packages:
source: hosted source: hosted
version: "1.15.0" version: "1.15.0"
convert: convert:
dependency: transitive dependency: "direct main"
description: description:
name: convert name: convert
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.0" version: "3.0.0"
crypto: crypto:
dependency: transitive dependency: "direct main"
description: description:
name: crypto name: crypto
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
@ -103,7 +103,7 @@ packages:
name: flutter_cache_manager name: flutter_cache_manager
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "3.0.0-nullsafety.1" version: "3.1.2"
flutter_test: flutter_test:
dependency: "direct dev" dependency: "direct dev"
description: flutter description: flutter
@ -311,7 +311,7 @@ packages:
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
uuid: uuid:
dependency: transitive dependency: "direct main"
description: description:
name: uuid name: uuid
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"

View File

@ -26,8 +26,12 @@ dependencies:
# Use with the CupertinoIcons class for iOS style icons. # Use with the CupertinoIcons class for iOS style icons.
cupertino_icons: ^1.0.2 cupertino_icons: ^1.0.2
convert: ^3.0.0
crypto: ^3.0.0
uuid: ^3.0.1
image: ^3.0.1 image: ^3.0.1
flutter_cache_manager: ^3.0.0-nullsafety.1 flutter_cache_manager: ^3.1.2
dev_dependencies: dev_dependencies:
flutter_test: flutter_test:

View File

@ -15,7 +15,8 @@ class WechatLaunchFromWXReq extends WechatSdkReq {
required this.country, required this.country,
}) : super(openId: openId); }) : super(openId: openId);
factory WechatLaunchFromWXReq.fromJson(Map<String, dynamic> json) => _$WechatLaunchFromWXReqFromJson(json); factory WechatLaunchFromWXReq.fromJson(Map<String, dynamic> json) =>
_$WechatLaunchFromWXReqFromJson(json);
final String? messageAction; final String? messageAction;
final String? messageExt; final String? messageExt;

View File

@ -15,7 +15,8 @@ class WechatShowMessageFromWXReq extends WechatSdkReq {
required this.country, required this.country,
}) : super(openId: openId); }) : super(openId: openId);
factory WechatShowMessageFromWXReq.fromJson(Map<String, dynamic> json) => _$WechatShowMessageFromWXReqFromJson(json); factory WechatShowMessageFromWXReq.fromJson(Map<String, dynamic> json) =>
_$WechatShowMessageFromWXReqFromJson(json);
final String? messageAction; final String? messageAction;
final String? messageExt; final String? messageExt;

View File

@ -6,10 +6,6 @@ import 'dart:typed_data';
import 'package:convert/convert.dart'; import 'package:convert/convert.dart';
import 'package:crypto/crypto.dart'; import 'package:crypto/crypto.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:uuid/uuid.dart';
import 'package:wechat_kit/src/model/api/wechat_access_token_resp.dart';
import 'package:wechat_kit/src/model/api/wechat_ticket_resp.dart';
import 'package:wechat_kit/src/model/api/wechat_user_info_resp.dart';
import 'package:wechat_kit/src/model/qrauth/wechat_qrauth_resp.dart'; import 'package:wechat_kit/src/model/qrauth/wechat_qrauth_resp.dart';
import 'package:wechat_kit/src/model/sdk/wechat_auth_resp.dart'; import 'package:wechat_kit/src/model/sdk/wechat_auth_resp.dart';
import 'package:wechat_kit/src/model/sdk/wechat_launch_from_wx_req.dart'; import 'package:wechat_kit/src/model/sdk/wechat_launch_from_wx_req.dart';
@ -118,7 +114,8 @@ class Wechat {
const MethodChannel('v7lin.github.io/wechat_kit') const MethodChannel('v7lin.github.io/wechat_kit')
..setMethodCallHandler(_handleMethod); ..setMethodCallHandler(_handleMethod);
final StreamController<WechatLaunchFromWXReq> _launchFromWXReqStreamController = final StreamController<WechatLaunchFromWXReq>
_launchFromWXReqStreamController =
StreamController<WechatLaunchFromWXReq>.broadcast(); StreamController<WechatLaunchFromWXReq>.broadcast();
final StreamController<WechatAuthResp> _authRespStreamController = final StreamController<WechatAuthResp> _authRespStreamController =
@ -173,7 +170,8 @@ class Wechat {
switch (call.method) { switch (call.method) {
// onReq // onReq
case _METHOD_LAUNCHFROMWX: case _METHOD_LAUNCHFROMWX:
_launchFromWXReqStreamController.add(WechatLaunchFromWXReq.fromJson((call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>())); _launchFromWXReqStreamController.add(WechatLaunchFromWXReq.fromJson(
(call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>()));
break; break;
// onResp // onResp
case _METHOD_ONAUTHRESP: case _METHOD_ONAUTHRESP:
@ -283,7 +281,8 @@ class Wechat {
/// 判断当前微信的版本是否支持分享微信状态功能 /// 判断当前微信的版本是否支持分享微信状态功能
Future<bool> isSupportStateAPI() async { Future<bool> isSupportStateAPI() async {
return await _channel.invokeMethod<bool>(_METHOD_ISSUPPORTSTATEAPI) ?? false; return await _channel.invokeMethod<bool>(_METHOD_ISSUPPORTSTATEAPI) ??
false;
} }
/// 打开微信 /// 打开微信
@ -304,121 +303,17 @@ class Wechat {
}); });
} }
/// 获取 access_tokenUnionID
Future<WechatAccessTokenResp> getAccessTokenUnionID({
required String appId,
required String appSecret,
required String code,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/oauth2/access_token?appid=$appId&secret=$appSecret&code=$code&grant_type=authorization_code'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 刷新或续期 access_token 使用UnionID
Future<WechatAccessTokenResp> refreshAccessTokenUnionID({
required String appId,
required String refreshToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/oauth2/refresh_token?appid=$appId&grant_type=refresh_token&refresh_token=$refreshToken'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 获取用户个人信息UnionID
Future<WechatUserInfoResp> getUserInfoUnionID({
required String openId,
required String accessToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/sns/userinfo?access_token=$accessToken&openid=$openId'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatUserInfoResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
// --- 微信APP扫码登录 // --- 微信APP扫码登录
/// 获取 access_token /// 调用微信 API 获得 ticket开始扫码登录
Future<WechatAccessTokenResp> getAccessToken({
required String appId,
required String appSecret,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=$appId&secret=$appSecret'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatAccessTokenResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 用上面的函数拿到的 access_token获取 sdk_ticket
Future<WechatTicketResp> getTicket({
required String accessToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=$accessToken&type=2'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final String content = await utf8.decodeStream(response);
return WechatTicketResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// 用上面函数拿到的 ticket开始扫码登录
Future<void> startQrauth({ Future<void> startQrauth({
required String appId, required String appId,
required List<String> scope, required List<String> scope,
required String noncestr,
required String ticket, required String ticket,
}) { }) {
final String noncestr = const Uuid().v1().toString().replaceAll('-', ''); // final String noncestr = const Uuid().v1().toString().replaceAll('-', '');
final String timestamp = DateTime.now().millisecondsSinceEpoch.toString(); final String timestamp = '${DateTime.now().millisecondsSinceEpoch}';
final String content = final String content =
'appid=$appId&noncestr=$noncestr&sdk_ticket=$ticket&timestamp=$timestamp'; 'appid=$appId&noncestr=$noncestr&sdk_ticket=$ticket&timestamp=$timestamp';
final String signature = final String signature =

View File

@ -1,9 +1,5 @@
library wechat_kit; library wechat_kit;
export 'src/model/api/wechat_access_token_resp.dart';
export 'src/model/api/wechat_api_resp.dart';
export 'src/model/api/wechat_ticket_resp.dart';
export 'src/model/api/wechat_user_info_resp.dart';
export 'src/model/qrauth/wechat_qrauth_resp.dart'; export 'src/model/qrauth/wechat_qrauth_resp.dart';
export 'src/model/sdk/wechat_auth_resp.dart'; export 'src/model/sdk/wechat_auth_resp.dart';
export 'src/model/sdk/wechat_launch_mini_program_resp.dart'; export 'src/model/sdk/wechat_launch_mini_program_resp.dart';

View File

@ -408,13 +408,6 @@ packages:
url: "https://pub.flutter-io.cn" url: "https://pub.flutter-io.cn"
source: hosted source: hosted
version: "1.3.0" version: "1.3.0"
uuid:
dependency: "direct main"
description:
name: uuid
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.0.1"
vector_math: vector_math:
dependency: transitive dependency: transitive
description: description:

View File

@ -15,8 +15,6 @@ dependencies:
convert: ^3.0.0 convert: ^3.0.0
crypto: ^3.0.0 crypto: ^3.0.0
uuid: ^3.0.1
json_annotation: ^4.0.0 json_annotation: ^4.0.0
dev_dependencies: dev_dependencies: