This commit is contained in:
v7lin
2021-07-31 16:00:13 +08:00
parent e5eda4f329
commit e903ecf4dd
19 changed files with 90 additions and 79 deletions

View File

@ -4,6 +4,9 @@ import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_cache_manager/flutter_cache_manager.dart';
import 'package:tencent_kit/tencent_kit.dart';
import 'package:tencent_kit_example/model/api/tencent_user_info_resp.dart';
import 'package:tencent_kit_example/model/unionid/tencent_unionid_resp.dart';
import 'package:tencent_kit_example/tencent.dart';
const String _TENCENT_APPID = 'your tencent appId';

View File

@ -0,0 +1,20 @@
import 'package:json_annotation/json_annotation.dart';
abstract class TencentApiResp {
const TencentApiResp({
required this.ret,
this.msg,
});
/// 网络请求成功发送至服务器,并且服务器返回数据格式正确
/// 这里包括所请求业务操作失败的情况,例如没有授权等原因导致
static const int RET_SUCCESS = 0;
@JsonKey(
defaultValue: RET_SUCCESS,
)
final int ret;
final String? msg;
bool get isSuccessful => ret == RET_SUCCESS;
}

View File

@ -0,0 +1,97 @@
import 'package:json_annotation/json_annotation.dart';
import 'package:tencent_kit_example/model/api/tencent_api_resp.dart';
part 'tencent_user_info_resp.g.dart';
@JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
)
class TencentUserInfoResp extends TencentApiResp {
const TencentUserInfoResp({
required int ret,
String? msg,
this.isLost,
this.nickname,
this.gender,
this.genderType,
this.province,
this.city,
this.year,
this.constellation,
this.figureurl,
this.figureurl1,
this.figureurl2,
this.figureurlQq,
this.figureurlQq1,
this.figureurlQq2,
this.figureurlType,
this.isYellowVip,
this.vip,
this.yellowVipLevel,
this.level,
this.isYellowYearVip,
}) : super(ret: ret, msg: msg);
factory TencentUserInfoResp.fromJson(Map<String, dynamic> json) =>
_$TencentUserInfoRespFromJson(json);
final int? isLost;
final String? nickname;
final String? gender; // 男/女
final int? genderType; // 男/女 - 1
final String? province;
final String? city;
final String? year;
final String? constellation;
final String? figureurl;
@JsonKey(
name: 'figureurl_1',
)
final String? figureurl1;
@JsonKey(
name: 'figureurl_2',
)
final String? figureurl2;
final String? figureurlQq; // 140 * 140
@JsonKey(
name: 'figureurl_qq_1',
)
final String? figureurlQq1; // 大小为40×40像素的QQ头像URL。
@JsonKey(
name: 'figureurl_qq_2',
)
final String?
figureurlQq2; // 大小为100×100像素的QQ头像URL。需要注意不是所有的用户都拥有QQ的100x100的头像但40x40像素则是一定会有。
final String? figureurlType;
final String? isYellowVip;
final String? vip;
final String? yellowVipLevel;
final String? level;
final String? isYellowYearVip;
bool get isMale => gender == '';
bool get isFemale => gender == '';
String? get headImgUrl {
if (figureurlQq?.isNotEmpty ?? false) {
return figureurlQq;
}
if (figureurlQq2?.isNotEmpty ?? false) {
return figureurlQq2;
}
if (figureurlQq1?.isNotEmpty ?? false) {
return figureurlQq1;
}
if (figureurl2?.isNotEmpty ?? false) {
return figureurl2;
}
if (figureurl1?.isNotEmpty ?? false) {
return figureurl1;
}
return figureurl;
}
Map<String, dynamic> toJson() => _$TencentUserInfoRespToJson(this);
}

View File

@ -0,0 +1,61 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tencent_user_info_resp.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
TencentUserInfoResp _$TencentUserInfoRespFromJson(Map<String, dynamic> json) {
return TencentUserInfoResp(
ret: json['ret'] as int? ?? 0,
msg: json['msg'] as String?,
isLost: json['is_lost'] as int?,
nickname: json['nickname'] as String?,
gender: json['gender'] as String?,
genderType: json['gender_type'] as int?,
province: json['province'] as String?,
city: json['city'] as String?,
year: json['year'] as String?,
constellation: json['constellation'] as String?,
figureurl: json['figureurl'] as String?,
figureurl1: json['figureurl_1'] as String?,
figureurl2: json['figureurl_2'] as String?,
figureurlQq: json['figureurl_qq'] as String?,
figureurlQq1: json['figureurl_qq_1'] as String?,
figureurlQq2: json['figureurl_qq_2'] as String?,
figureurlType: json['figureurl_type'] as String?,
isYellowVip: json['is_yellow_vip'] as String?,
vip: json['vip'] as String?,
yellowVipLevel: json['yellow_vip_level'] as String?,
level: json['level'] as String?,
isYellowYearVip: json['is_yellow_year_vip'] as String?,
);
}
Map<String, dynamic> _$TencentUserInfoRespToJson(
TencentUserInfoResp instance) =>
<String, dynamic>{
'ret': instance.ret,
'msg': instance.msg,
'is_lost': instance.isLost,
'nickname': instance.nickname,
'gender': instance.gender,
'gender_type': instance.genderType,
'province': instance.province,
'city': instance.city,
'year': instance.year,
'constellation': instance.constellation,
'figureurl': instance.figureurl,
'figureurl_1': instance.figureurl1,
'figureurl_2': instance.figureurl2,
'figureurl_qq': instance.figureurlQq,
'figureurl_qq_1': instance.figureurlQq1,
'figureurl_qq_2': instance.figureurlQq2,
'figureurl_type': instance.figureurlType,
'is_yellow_vip': instance.isYellowVip,
'vip': instance.vip,
'yellow_vip_level': instance.yellowVipLevel,
'level': instance.level,
'is_yellow_year_vip': instance.isYellowYearVip,
};

View File

@ -0,0 +1,35 @@
import 'package:json_annotation/json_annotation.dart';
part 'tencent_unionid_resp.g.dart';
@JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
)
class TencentUnionidResp {
const TencentUnionidResp({
required this.error,
this.errorDescription,
this.clientId,
this.openid,
this.unionid,
});
factory TencentUnionidResp.fromJson(Map<String, dynamic> json) =>
_$TencentUnionidRespFromJson(json);
@JsonKey(
defaultValue: ERROR_SUCCESS,
)
final int error;
final String? errorDescription;
final String? clientId;
final String? openid;
final String? unionid;
static const int ERROR_SUCCESS = 0;
bool get isSuccessful => error == ERROR_SUCCESS;
Map<String, dynamic> toJson() => _$TencentUnionidRespToJson(this);
}

View File

@ -0,0 +1,26 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'tencent_unionid_resp.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
TencentUnionidResp _$TencentUnionidRespFromJson(Map<String, dynamic> json) {
return TencentUnionidResp(
error: json['error'] as int? ?? 0,
errorDescription: json['error_description'] as String?,
clientId: json['client_id'] as String?,
openid: json['openid'] as String?,
unionid: json['unionid'] as String?,
);
}
Map<String, dynamic> _$TencentUnionidRespToJson(TencentUnionidResp instance) =>
<String, dynamic>{
'error': instance.error,
'error_description': instance.errorDescription,
'client_id': instance.clientId,
'openid': instance.openid,
'unionid': instance.unionid,
};

69
example/lib/tencent.dart Normal file
View File

@ -0,0 +1,69 @@
import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:tencent_kit/tencent_kit.dart';
import 'package:tencent_kit_example/model/api/tencent_user_info_resp.dart';
import 'package:tencent_kit_example/model/unionid/tencent_unionid_resp.dart';
extension MixerTencent on Tencent {
/// 用户信息
/// https://wiki.connect.qq.com/get_user_info
Future<TencentUserInfoResp> getUserInfo({
required String appId,
required String openid,
required String accessToken,
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://graph.qq.com/user/get_user_info?access_token=$accessToken&oauth_consumer_key=$appId&openid=$openid'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final ContentType? contentType = response.headers.contentType;
final Encoding encoding =
Encoding.getByName(contentType?.charset) ?? utf8;
final String content = await encoding.decodeStream(response);
return TencentUserInfoResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
/// UnionID
/// https://wiki.connect.qq.com/unionid%E4%BB%8B%E7%BB%8D
Future<TencentUnionidResp> getUnionId({
required String accessToken,
String unionid = '1',
}) {
return HttpClient()
.getUrl(Uri.parse(
'https://graph.qq.com/oauth2.0/me?access_token=$accessToken&unionid=$unionid'))
.then((HttpClientRequest request) {
return request.close();
}).then((HttpClientResponse response) async {
if (response.statusCode == HttpStatus.ok) {
final ContentType? contentType = response.headers.contentType;
final Encoding encoding =
Encoding.getByName(contentType?.charset) ?? utf8;
final String callback = await encoding.decodeStream(response);
// 腾讯有毒 callback( $json );
final RegExp exp = RegExp(r'callback\( (.*) \)\;');
final Match? match = exp.firstMatch(callback);
if (match?.groupCount == 1) {
final String? content = match!.group(1);
if (content != null) {
return TencentUnionidResp.fromJson(
json.decode(content) as Map<String, dynamic>);
}
}
}
throw HttpException(
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
});
}
}