fake_weibo 0.1.0
This commit is contained in:
parent
9538c6faa8
commit
59d1407e74
@ -74,7 +74,7 @@ dependencies:
|
||||
|
||||
### release
|
||||
````
|
||||
latestVersion = 0.0.1+1
|
||||
latestVersion = 0.1.0
|
||||
````
|
||||
|
||||
````
|
||||
|
@ -41,7 +41,7 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
channel.setMethodCallHandler(plugin);
|
||||
}
|
||||
|
||||
private static class FakeWeiboErrorCode {
|
||||
private static class WeiboErrorCode {
|
||||
public static final int SUCCESS = 0;//成功
|
||||
public static final int USERCANCEL = -1;//用户取消发送
|
||||
public static final int SENT_FAIL = -2;//发送失败
|
||||
@ -79,7 +79,7 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
private static final String ARGUMENT_KEY_RESULT_USERID = "userId";
|
||||
private static final String ARGUMENT_KEY_RESULT_ACCESSTOKEN = "accessToken";
|
||||
private static final String ARGUMENT_KEY_RESULT_REFRESHTOKEN = "refreshToken";
|
||||
private static final String ARGUMENT_KEY_RESULT_EXPIRATIONDATE = "expirationDate";
|
||||
private static final String ARGUMENT_KEY_RESULT_EXPIRESIN = "expiresIn";
|
||||
|
||||
private final Registrar registrar;
|
||||
private final MethodChannel channel;
|
||||
@ -125,13 +125,14 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
public void onSuccess(Oauth2AccessToken oauth2AccessToken) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
if (oauth2AccessToken.isSessionValid()) {
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.SUCCESS);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS);
|
||||
map.put(ARGUMENT_KEY_RESULT_USERID, oauth2AccessToken.getUid());
|
||||
map.put(ARGUMENT_KEY_RESULT_ACCESSTOKEN, oauth2AccessToken.getToken());
|
||||
map.put(ARGUMENT_KEY_RESULT_REFRESHTOKEN, oauth2AccessToken.getRefreshToken());
|
||||
map.put(ARGUMENT_KEY_RESULT_EXPIRATIONDATE, oauth2AccessToken.getExpiresTime());
|
||||
long expiresIn = (long) Math.ceil((oauth2AccessToken.getExpiresTime() - System.currentTimeMillis()) / 1000.0);
|
||||
map.put(ARGUMENT_KEY_RESULT_EXPIRESIN, expiresIn);// 向上取整
|
||||
} else {
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.UNKNOWN);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN);
|
||||
}
|
||||
channel.invokeMethod(METHOD_ONAUTHRESP, map);
|
||||
}
|
||||
@ -139,7 +140,7 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
@Override
|
||||
public void cancel() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.USERCANCEL);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL);
|
||||
channel.invokeMethod(METHOD_ONAUTHRESP, map);
|
||||
}
|
||||
|
||||
@ -148,12 +149,12 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
// 微博有毒,WbConnectErrorMessage对象两个属性设置错误
|
||||
if (TextUtils.equals(wbConnectErrorMessage.getErrorMessage(), "21338")) {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.SSO_PKG_SIGN_ERROR);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SSO_PKG_SIGN_ERROR);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORMESSAGE, wbConnectErrorMessage.getErrorCode());
|
||||
channel.invokeMethod(METHOD_ONAUTHRESP, map);
|
||||
} else {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.UNKNOWN);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.UNKNOWN);
|
||||
channel.invokeMethod(METHOD_ONAUTHRESP, map);
|
||||
}
|
||||
}
|
||||
@ -218,21 +219,21 @@ public class FakeWeiboPlugin implements MethodCallHandler, PluginRegistry.Activi
|
||||
@Override
|
||||
public void onWbShareSuccess() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.SUCCESS);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SUCCESS);
|
||||
channel.invokeMethod(METHOD_ONSHAREMSGRESP, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWbShareCancel() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.USERCANCEL);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.USERCANCEL);
|
||||
channel.invokeMethod(METHOD_ONSHAREMSGRESP, map);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onWbShareFail() {
|
||||
Map<String, Object> map = new HashMap<>();
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, FakeWeiboErrorCode.SHARE_IN_SDK_FAILED);
|
||||
map.put(ARGUMENT_KEY_RESULT_ERRORCODE, WeiboErrorCode.SHARE_IN_SDK_FAILED);
|
||||
channel.invokeMethod(METHOD_ONSHAREMSGRESP, map);
|
||||
}
|
||||
});
|
||||
|
@ -8,7 +8,6 @@
|
||||
|
||||
/* Begin PBXBuildFile section */
|
||||
1498D2341E8E89220040F4C2 /* GeneratedPluginRegistrant.m in Sources */ = {isa = PBXBuildFile; fileRef = 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */; };
|
||||
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */ = {isa = PBXBuildFile; fileRef = 2D5378251FAA1A9400D5DBA9 /* flutter_assets */; };
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */ = {isa = PBXBuildFile; fileRef = 3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */; };
|
||||
3B80C3941E831B6300D905FE /* App.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; };
|
||||
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||
@ -41,7 +40,6 @@
|
||||
/* Begin PBXFileReference section */
|
||||
1498D2321E8E86230040F4C2 /* GeneratedPluginRegistrant.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = GeneratedPluginRegistrant.h; sourceTree = "<group>"; };
|
||||
1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = "<group>"; };
|
||||
2D5378251FAA1A9400D5DBA9 /* flutter_assets */ = {isa = PBXFileReference; lastKnownFileType = folder; name = flutter_assets; path = Flutter/flutter_assets; sourceTree = SOURCE_ROOT; };
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = AppFrameworkInfo.plist; path = Flutter/AppFrameworkInfo.plist; sourceTree = "<group>"; };
|
||||
3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = "<group>"; };
|
||||
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
|
||||
@ -83,7 +81,6 @@
|
||||
9740EEB11CF90186004384FC /* Flutter */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
2D5378251FAA1A9400D5DBA9 /* flutter_assets */,
|
||||
3B80C3931E831B6300D905FE /* App.framework */,
|
||||
3B3967151E833CAA004F5970 /* AppFrameworkInfo.plist */,
|
||||
9740EEBA1CF902C7004384FC /* Flutter.framework */,
|
||||
@ -213,7 +210,6 @@
|
||||
3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */,
|
||||
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */,
|
||||
97C146FE1CF9000F007C117D /* Assets.xcassets in Resources */,
|
||||
2D5378261FAA1A9400D5DBA9 /* flutter_assets in Resources */,
|
||||
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */,
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
|
@ -6,6 +6,9 @@ import 'package:flutter/services.dart';
|
||||
import 'package:fake_weibo/fake_weibo.dart';
|
||||
|
||||
const String _WEIBO_APP_KEY = '3393861383';
|
||||
const List<String> _WEIBO_SCOPE = <String>[
|
||||
WeiboScope.ALL,
|
||||
];
|
||||
|
||||
void main() {
|
||||
runZoned(() {
|
||||
@ -25,14 +28,12 @@ void main() {
|
||||
class MyApp extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
FakeWeibo weibo = FakeWeibo(
|
||||
appKey: _WEIBO_APP_KEY,
|
||||
scope: [
|
||||
FakeWeiboScope.ALL,
|
||||
],
|
||||
);
|
||||
weibo.registerApp();
|
||||
return FakeWeiboProvider(
|
||||
Weibo weibo = Weibo()
|
||||
..registerApp(
|
||||
appKey: _WEIBO_APP_KEY,
|
||||
scope: _WEIBO_SCOPE,
|
||||
);
|
||||
return WeiboProvider(
|
||||
weibo: weibo,
|
||||
child: MaterialApp(
|
||||
home: Home(
|
||||
@ -46,7 +47,7 @@ class MyApp extends StatelessWidget {
|
||||
class Home extends StatefulWidget {
|
||||
Home({Key key, @required this.weibo}) : super(key: key);
|
||||
|
||||
final FakeWeibo weibo;
|
||||
final Weibo weibo;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() {
|
||||
@ -55,10 +56,10 @@ class Home extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _HomeState extends State<Home> {
|
||||
StreamSubscription<FakeWeiboAuthResp> _auth;
|
||||
StreamSubscription<FakeWeiboShareMsgResp> _share;
|
||||
StreamSubscription<WeiboAuthResp> _auth;
|
||||
StreamSubscription<WeiboSdkResp> _share;
|
||||
|
||||
FakeWeiboAuthResp _authResp;
|
||||
WeiboAuthResp _authResp;
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@ -67,13 +68,13 @@ class _HomeState extends State<Home> {
|
||||
_share = widget.weibo.shareMsgResp().listen(_listenShareMsg);
|
||||
}
|
||||
|
||||
void _listenAuth(FakeWeiboAuthResp resp) {
|
||||
void _listenAuth(WeiboAuthResp resp) {
|
||||
_authResp = resp;
|
||||
String content = 'auth: ${resp.errorCode}';
|
||||
_showTips('登录', content);
|
||||
}
|
||||
|
||||
void _listenShareMsg(FakeWeiboShareMsgResp resp) {
|
||||
void _listenShareMsg(WeiboSdkResp resp) {
|
||||
String content = 'share: ${resp.errorCode}';
|
||||
_showTips('分享', content);
|
||||
}
|
||||
@ -108,26 +109,29 @@ class _HomeState extends State<Home> {
|
||||
ListTile(
|
||||
title: Text('登录'),
|
||||
onTap: () {
|
||||
widget.weibo.auth();
|
||||
widget.weibo.auth(
|
||||
appKey: _WEIBO_APP_KEY,
|
||||
scope: _WEIBO_SCOPE,
|
||||
);
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text('用户信息'),
|
||||
onTap: () async {
|
||||
if (_authResp != null &&
|
||||
_authResp.errorCode == FakeWeiboErrorCode.SUCCESS) {
|
||||
FakeWeiboApiUserResp userResp = await widget.weibo.getUserInfo(
|
||||
appkey: _WEIBO_APP_KEY,
|
||||
userId: _authResp.userId,
|
||||
accessToken: _authResp.accessToken);
|
||||
if (userResp != null &&
|
||||
userResp.errorCode ==
|
||||
FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS) {
|
||||
_authResp.errorCode == WeiboSdkResp.SUCCESS) {
|
||||
WeiboUserInfoResp userInfoResp = await widget.weibo.getUserInfo(
|
||||
appkey: _WEIBO_APP_KEY,
|
||||
userId: _authResp.userId,
|
||||
accessToken: _authResp.accessToken,
|
||||
);
|
||||
if (userInfoResp != null &&
|
||||
userInfoResp.errorCode == WeiboApiResp.ERROR_CODE_SUCCESS) {
|
||||
_showTips('用户信息',
|
||||
'${userResp.screenName}\n${userResp.description}\n${userResp.location}\n${userResp.profileImageUrl}');
|
||||
'${userInfoResp.screenName}\n${userInfoResp.description}\n${userInfoResp.location}\n${userInfoResp.profileImageUrl}');
|
||||
} else {
|
||||
_showTips('用户信息',
|
||||
'获取用户信息失败\n${userResp.errorCode}:${userResp.error}');
|
||||
'获取用户信息失败\n${userInfoResp.errorCode}:${userInfoResp.error}');
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -43,7 +43,7 @@ static NSString * const ARGUMENT_KEY_RESULT_ERRORMESSAGE = @"errorMessage";
|
||||
static NSString * const ARGUMENT_KEY_RESULT_USERID = @"userId";
|
||||
static NSString * const ARGUMENT_KEY_RESULT_ACCESSTOKEN = @"accessToken";
|
||||
static NSString * const ARGUMENT_KEY_RESULT_REFRESHTOKEN = @"refreshToken";
|
||||
static NSString * const ARGUMENT_KEY_RESULT_EXPIRATIONDATE = @"expirationDate";
|
||||
static NSString * const ARGUMENT_KEY_RESULT_EXPIRESIN = @"expiresIn";
|
||||
|
||||
-(instancetype)initWithChannel:(FlutterMethodChannel *)channel {
|
||||
self = [super init];
|
||||
@ -145,11 +145,11 @@ static NSString * const ARGUMENT_KEY_RESULT_EXPIRATIONDATE = @"expirationDate";
|
||||
NSString * userId = authorizeResponse.userID;
|
||||
NSString * accessToken = authorizeResponse.accessToken;
|
||||
NSString * refreshToken = authorizeResponse.refreshToken;
|
||||
long long expirationDate = authorizeResponse.expirationDate.timeIntervalSince1970 * 1000;
|
||||
long long expiresIn = ceil(authorizeResponse.expirationDate.timeIntervalSinceNow);// 向上取整
|
||||
[dictionary setValue:userId forKey:ARGUMENT_KEY_RESULT_USERID];
|
||||
[dictionary setValue:accessToken forKey:ARGUMENT_KEY_RESULT_ACCESSTOKEN];
|
||||
[dictionary setValue:refreshToken forKey:ARGUMENT_KEY_RESULT_REFRESHTOKEN];
|
||||
[dictionary setValue:[NSNumber numberWithLongLong:expirationDate] forKey:ARGUMENT_KEY_RESULT_EXPIRATIONDATE];
|
||||
[dictionary setValue:[NSNumber numberWithLongLong:expiresIn] forKey:ARGUMENT_KEY_RESULT_EXPIRESIN];
|
||||
}
|
||||
[_channel invokeMethod:METHOD_ONAUTHRESP arguments:dictionary];
|
||||
} else if ([response isKindOfClass:[WBSendMessageToWeiboResponse class]]) {
|
||||
|
@ -1,529 +1,9 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class FakeWeiboScope {
|
||||
FakeWeiboScope._();
|
||||
|
||||
static const String EMAIL = 'email';
|
||||
static const String DIRECT_MESSAGES_READ = 'direct_messages_read';
|
||||
static const String DIRECT_MESSAGES_WRITE = 'direct_messages_write';
|
||||
static const String FRIENDSHIPS_GROUPS_READ = 'friendships_groups_read';
|
||||
static const String FRIENDSHIPS_GROUPS_WRITE = 'friendships_groups_write';
|
||||
static const String STATUSES_TO_ME_READ = 'statuses_to_me_read';
|
||||
static const String FOLLOW_APP_OFFICIAL_MICROBLOG =
|
||||
'follow_app_official_microblog';
|
||||
static const String INVITATION_WRITE = 'invitation_write';
|
||||
static const String ALL = 'all';
|
||||
}
|
||||
|
||||
class FakeWeiboErrorCode {
|
||||
FakeWeiboErrorCode._();
|
||||
|
||||
/// 成功
|
||||
static const int SUCCESS = 0;
|
||||
|
||||
/// 用户取消发送
|
||||
static const int USERCANCEL = -1;
|
||||
|
||||
/// 发送失败
|
||||
static const int SENT_FAIL = -2;
|
||||
|
||||
/// 授权失败
|
||||
static const int AUTH_DENY = -3;
|
||||
|
||||
/// 用户取消安装微博客户端
|
||||
static const int USERCANCEL_INSTALL = -4;
|
||||
|
||||
/// 支付失败
|
||||
static const int PAY_FAIL = -5;
|
||||
|
||||
/// 分享失败 详情见response UserInfo
|
||||
static const int SHARE_IN_SDK_FAILED = -8;
|
||||
|
||||
/// 不支持的请求
|
||||
static const int UNSUPPORT = -99;
|
||||
|
||||
/// 未知
|
||||
static const int UNKNOWN = -100;
|
||||
|
||||
/// sso package or sign error
|
||||
static const int SSO_PKG_SIGN_ERROR = 21338;
|
||||
}
|
||||
|
||||
abstract class FakeWeiboBaseResp {
|
||||
FakeWeiboBaseResp({
|
||||
@required this.errorCode,
|
||||
this.errorMessage,
|
||||
});
|
||||
|
||||
final int errorCode;
|
||||
final String errorMessage;
|
||||
}
|
||||
|
||||
class FakeWeiboAuthResp extends FakeWeiboBaseResp {
|
||||
FakeWeiboAuthResp._({
|
||||
@required int errorCode,
|
||||
String errorMessage,
|
||||
this.userId,
|
||||
this.accessToken,
|
||||
this.refreshToken,
|
||||
this.expirationDate,
|
||||
}) : super(
|
||||
errorCode: errorCode,
|
||||
errorMessage: errorMessage,
|
||||
);
|
||||
|
||||
final String userId;
|
||||
final String accessToken;
|
||||
final String refreshToken;
|
||||
final int expirationDate;
|
||||
}
|
||||
|
||||
class FakeWeiboShareMsgResp extends FakeWeiboBaseResp {
|
||||
FakeWeiboShareMsgResp._({
|
||||
@required int errorCode,
|
||||
String errorMessage,
|
||||
}) : super(
|
||||
errorCode: errorCode,
|
||||
errorMessage: errorMessage,
|
||||
);
|
||||
}
|
||||
|
||||
abstract class FakeWeiboApiBaseResp {
|
||||
FakeWeiboApiBaseResp({
|
||||
@required this.errorCode,
|
||||
this.error,
|
||||
this.request,
|
||||
});
|
||||
|
||||
static const String KEY_ERROR_CODE = 'error_code';
|
||||
static const String KEY_ERROR = 'error';
|
||||
static const String KEY_REQUEST = 'request';
|
||||
|
||||
static const int ERROR_CODE_SUCCESS = 0;
|
||||
|
||||
/// https://open.weibo.com/wiki/Help/error
|
||||
final int errorCode;
|
||||
final String error;
|
||||
final String request;
|
||||
}
|
||||
|
||||
class FakeWeiboApiUserResp extends FakeWeiboApiBaseResp {
|
||||
FakeWeiboApiUserResp._({
|
||||
int errorCode,
|
||||
String error,
|
||||
String request,
|
||||
this.id,
|
||||
this.idstr,
|
||||
this.screenName,
|
||||
this.name,
|
||||
this.province,
|
||||
this.city,
|
||||
this.location,
|
||||
this.description,
|
||||
this.url,
|
||||
this.profileImageUrl,
|
||||
this.profileUrl,
|
||||
this.domain,
|
||||
this.weihao,
|
||||
this.gender,
|
||||
this.verified,
|
||||
this.avatarLarge,
|
||||
this.avatarHD,
|
||||
}) : super(errorCode: errorCode, error: error, request: request);
|
||||
|
||||
static const String KEY_ID = 'id';
|
||||
static const String KEY_ID_STR = 'idstr';
|
||||
static const String KEY_SCREEN_NAME = 'screen_name';
|
||||
static const String KEY_NAME = 'name';
|
||||
static const String KEY_PROVINCE = 'province';
|
||||
static const String KEY_CITY = 'city';
|
||||
static const String KEY_LOCATION = 'location';
|
||||
static const String KEY_DESCRIPTION = 'description';
|
||||
static const String KEY_URL = 'url';
|
||||
static const String KEY_PROFILE_IMAGE_URL = 'profile_image_url';
|
||||
static const String KEY_PROFILE_URL = 'profile_url';
|
||||
static const String KEY_DOMAIN = 'domain';
|
||||
static const String KEY_WEIHAO = 'weihao';
|
||||
static const String KEY_GENDER = 'gender';
|
||||
static const String KEY_VERIFIED = 'verified';
|
||||
static const String KEY_AVATAR_LARGE = 'avatar_large';
|
||||
static const String KEY_AVATAR_HD = 'avatar_hd';
|
||||
|
||||
/// 用户UID(int64)
|
||||
final int id;
|
||||
|
||||
/// 字符串型的用户 UID
|
||||
final String idstr;
|
||||
|
||||
/// 用户昵称
|
||||
final String screenName;
|
||||
|
||||
/// 友好显示名称
|
||||
final String name;
|
||||
|
||||
/// 用户所在省级ID
|
||||
final String province;
|
||||
|
||||
/// 用户所在城市ID
|
||||
final String city;
|
||||
|
||||
/// 用户所在地
|
||||
final String location;
|
||||
|
||||
/// 用户个人描述
|
||||
final String description;
|
||||
|
||||
/// 用户博客地址
|
||||
final String url;
|
||||
|
||||
/// 用户头像地址,50×50像素
|
||||
final String profileImageUrl;
|
||||
|
||||
/// 用户的微博统一URL地址
|
||||
final String profileUrl;
|
||||
|
||||
/// 用户的个性化域名
|
||||
final String domain;
|
||||
|
||||
/// 用户的微号
|
||||
final String weihao;
|
||||
|
||||
/// 性别,m:男、f:女、n:未知
|
||||
final String gender;
|
||||
|
||||
// /// 粉丝数
|
||||
// final int followers_count;
|
||||
|
||||
// /// 关注数
|
||||
// final int friends_count;
|
||||
|
||||
// /// 微博数
|
||||
// final int statuses_count;
|
||||
|
||||
// /// 收藏数
|
||||
// final int favourites_count;
|
||||
|
||||
// /// 用户创建(注册)时间
|
||||
// final String created_at;
|
||||
|
||||
// /// 暂未支持
|
||||
// final bool following;
|
||||
|
||||
// /// 是否允许所有人给我发私信,true:是,false:否
|
||||
// final bool allow_all_act_msg;
|
||||
|
||||
// /// 是否允许标识用户的地理位置,true:是,false:否
|
||||
// final bool geo_enabled;
|
||||
|
||||
/// 是否是微博认证用户,即加V用户,true:是,false:否
|
||||
final bool verified;
|
||||
|
||||
// /// 暂未支持
|
||||
// final int verified_type;
|
||||
|
||||
// /// 用户备注信息,只有在查询用户关系时才返回此字段
|
||||
// final String remark;
|
||||
|
||||
// /// 用户的最近一条微博信息字段
|
||||
// final dynamic status;
|
||||
|
||||
// /// 是否允许所有人对我的微博进行评论,true:是,false:否
|
||||
// final bool allow_all_comment;
|
||||
|
||||
/// 用户大头像地址
|
||||
final String avatarLarge;
|
||||
|
||||
/// 用户高清大头像地址
|
||||
final String avatarHD;
|
||||
|
||||
// /// 认证原因
|
||||
// final String verified_reason;
|
||||
|
||||
// /// 该用户是否关注当前登录用户,true:是,false:否
|
||||
// final bool follow_me;
|
||||
|
||||
// /// 用户的在线状态,0:不在线、1:在线
|
||||
// final int online_status;
|
||||
|
||||
// /// 用户的互粉数
|
||||
// final int bi_followers_count;
|
||||
|
||||
// /// 用户当前的语言版本,zh-cn:简体中文,zh-tw:繁体中文,en:英语
|
||||
// final String lang;
|
||||
|
||||
// /// 注意:以下字段暂时不清楚具体含义,OpenAPI 说明文档暂时没有同步更新对应字段
|
||||
// final String star;
|
||||
// final String mbtype;
|
||||
// final String mbrank;
|
||||
// final String block_word;
|
||||
}
|
||||
|
||||
class FakeWeibo {
|
||||
FakeWeibo({
|
||||
@required String appKey,
|
||||
@required List<String> scope,
|
||||
String redirectUrl = _DEFAULT_REDIRECTURL,
|
||||
}) : assert(appKey != null && appKey.isNotEmpty),
|
||||
assert(scope != null && scope.isNotEmpty),
|
||||
_appKey = appKey,
|
||||
_scope = scope,
|
||||
_redirectUrl = redirectUrl;
|
||||
|
||||
static const String _METHOD_REGISTERAPP = 'registerApp';
|
||||
static const String _METHOD_ISWEIBOINSTALLED = 'isWeiboInstalled';
|
||||
static const String _METHOD_AUTH = 'auth';
|
||||
static const String _METHOD_SHARETEXT = 'shareText';
|
||||
static const String _METHOD_SHAREIMAGE = 'shareImage';
|
||||
static const String _METHOD_SHAREWEBPAGE = 'shareWebpage';
|
||||
|
||||
static const String _METHOD_ONAUTHRESP = 'onAuthResp';
|
||||
static const String _METHOD_ONSHAREMSGRESP = 'onShareMsgResp';
|
||||
|
||||
static const String _ARGUMENT_KEY_APPKEY = 'appKey';
|
||||
static const String _ARGUMENT_KEY_SCOPE = 'scope';
|
||||
static const String _ARGUMENT_KEY_REDIRECTURL = 'redirectUrl';
|
||||
static const String _ARGUMENT_KEY_TEXT = 'text';
|
||||
static const String _ARGUMENT_KEY_TITLE = 'title';
|
||||
static const String _ARGUMENT_KEY_DESCRIPTION = 'description';
|
||||
static const String _ARGUMENT_KEY_THUMBDATA = 'thumbData';
|
||||
static const String _ARGUMENT_KEY_IMAGEDATA = 'imageData';
|
||||
static const String _ARGUMENT_KEY_WEBPAGEURL = 'webpageUrl';
|
||||
|
||||
static const String _ARGUMENT_KEY_RESULT_ERRORCODE = "errorCode";
|
||||
static const String _ARGUMENT_KEY_RESULT_ERRORMESSAGE = "errorMessage";
|
||||
static const String _ARGUMENT_KEY_RESULT_USERID = 'userId';
|
||||
static const String _ARGUMENT_KEY_RESULT_ACCESSTOKEN = 'accessToken';
|
||||
static const String _ARGUMENT_KEY_RESULT_REFRESHTOKEN = 'refreshToken';
|
||||
static const String _ARGUMENT_KEY_RESULT_EXPIRATIONDATE = 'expirationDate';
|
||||
|
||||
static const String _DEFAULT_REDIRECTURL =
|
||||
'https://api.weibo.com/oauth2/default.html';
|
||||
|
||||
static const MethodChannel _channel =
|
||||
MethodChannel('v7lin.github.io/fake_weibo');
|
||||
|
||||
final String _appKey;
|
||||
final List<String> _scope;
|
||||
|
||||
/// 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置
|
||||
final String _redirectUrl;
|
||||
|
||||
final StreamController<FakeWeiboAuthResp> _authRespStreamController =
|
||||
StreamController<FakeWeiboAuthResp>.broadcast();
|
||||
|
||||
final StreamController<FakeWeiboShareMsgResp> _shareMsgRespStreamController =
|
||||
StreamController<FakeWeiboShareMsgResp>.broadcast();
|
||||
|
||||
Future<void> registerApp() {
|
||||
_channel.setMethodCallHandler(_handleMethod);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_REGISTERAPP,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_APPKEY: _appKey,
|
||||
_ARGUMENT_KEY_SCOPE: _scope.join(','),
|
||||
_ARGUMENT_KEY_REDIRECTURL: _redirectUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case _METHOD_ONAUTHRESP:
|
||||
_authRespStreamController.add(FakeWeiboAuthResp._(
|
||||
errorCode: call.arguments[_ARGUMENT_KEY_RESULT_ERRORCODE] as int,
|
||||
errorMessage: call.arguments[_ARGUMENT_KEY_RESULT_ERRORMESSAGE] as String,
|
||||
userId: call.arguments[_ARGUMENT_KEY_RESULT_USERID] as String,
|
||||
accessToken:
|
||||
call.arguments[_ARGUMENT_KEY_RESULT_ACCESSTOKEN] as String,
|
||||
refreshToken:
|
||||
call.arguments[_ARGUMENT_KEY_RESULT_REFRESHTOKEN] as String,
|
||||
expirationDate:
|
||||
call.arguments[_ARGUMENT_KEY_RESULT_EXPIRATIONDATE] as int,
|
||||
));
|
||||
break;
|
||||
case _METHOD_ONSHAREMSGRESP:
|
||||
_shareMsgRespStreamController.add(FakeWeiboShareMsgResp._(
|
||||
errorCode: call.arguments[_ARGUMENT_KEY_RESULT_ERRORCODE] as int,
|
||||
errorMessage: call.arguments[_ARGUMENT_KEY_RESULT_ERRORMESSAGE] as String,
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream<FakeWeiboAuthResp> authResp() {
|
||||
return _authRespStreamController.stream;
|
||||
}
|
||||
|
||||
Stream<FakeWeiboShareMsgResp> shareMsgResp() {
|
||||
return _shareMsgRespStreamController.stream;
|
||||
}
|
||||
|
||||
Future<bool> isWeiboInstalled() async {
|
||||
return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool;
|
||||
}
|
||||
|
||||
Future<void> auth() {
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_AUTH,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_APPKEY: _appKey,
|
||||
_ARGUMENT_KEY_SCOPE: _scope.join(','),
|
||||
_ARGUMENT_KEY_REDIRECTURL: _redirectUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<FakeWeiboApiUserResp> getUserInfo({
|
||||
@required String appkey,
|
||||
@required String userId,
|
||||
@required String accessToken,
|
||||
}) {
|
||||
assert(userId != null && userId.isNotEmpty);
|
||||
assert(accessToken != null && accessToken.isNotEmpty);
|
||||
Map<String, String> params = <String, String>{
|
||||
'uid': userId,
|
||||
};
|
||||
return HttpClient()
|
||||
.getUrl(_encodeUrl('https://api.weibo.com/2/users/show.json', appkey,
|
||||
accessToken, params))
|
||||
.then((HttpClientRequest request) {
|
||||
return request.close();
|
||||
}).then((HttpClientResponse response) async {
|
||||
if (response.statusCode == HttpStatus.ok) {
|
||||
String content = await utf8.decodeStream(response);
|
||||
Map<dynamic, dynamic> map = json.decode(content) as Map<dynamic, dynamic>;
|
||||
int errorCode = map.containsKey(FakeWeiboApiBaseResp.KEY_ERROR_CODE)
|
||||
? map[FakeWeiboApiBaseResp.KEY_ERROR_CODE] as int
|
||||
: FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS;
|
||||
if (errorCode == FakeWeiboApiBaseResp.ERROR_CODE_SUCCESS) {
|
||||
return FakeWeiboApiUserResp._(
|
||||
errorCode: errorCode,
|
||||
id: map[FakeWeiboApiUserResp.KEY_ID] as int,
|
||||
idstr: map[FakeWeiboApiUserResp.KEY_ID_STR] as String,
|
||||
screenName: map[FakeWeiboApiUserResp.KEY_SCREEN_NAME] as String,
|
||||
name: map[FakeWeiboApiUserResp.KEY_NAME] as String,
|
||||
province: map[FakeWeiboApiUserResp.KEY_PROVINCE] as String,
|
||||
city: map[FakeWeiboApiUserResp.KEY_CITY] as String,
|
||||
location: map[FakeWeiboApiUserResp.KEY_LOCATION] as String,
|
||||
description: map[FakeWeiboApiUserResp.KEY_DESCRIPTION] as String,
|
||||
url: map[FakeWeiboApiUserResp.KEY_URL] as String,
|
||||
profileImageUrl:
|
||||
map[FakeWeiboApiUserResp.KEY_PROFILE_IMAGE_URL] as String,
|
||||
profileUrl: map[FakeWeiboApiUserResp.KEY_PROFILE_URL] as String,
|
||||
domain: map[FakeWeiboApiUserResp.KEY_DOMAIN] as String,
|
||||
weihao: map[FakeWeiboApiUserResp.KEY_WEIHAO] as String,
|
||||
gender: map[FakeWeiboApiUserResp.KEY_GENDER] as String,
|
||||
verified: map[FakeWeiboApiUserResp.KEY_VERIFIED] as bool,
|
||||
avatarLarge: map[FakeWeiboApiUserResp.KEY_AVATAR_LARGE] as String,
|
||||
avatarHD: map[FakeWeiboApiUserResp.KEY_AVATAR_HD] as String,
|
||||
);
|
||||
} else {
|
||||
return FakeWeiboApiUserResp._(
|
||||
errorCode: errorCode,
|
||||
error: map[FakeWeiboApiBaseResp.KEY_ERROR] as String,
|
||||
request: map[FakeWeiboApiBaseResp.KEY_REQUEST] as String,
|
||||
);
|
||||
}
|
||||
}
|
||||
throw HttpException(
|
||||
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
|
||||
});
|
||||
}
|
||||
|
||||
Uri _encodeUrl(
|
||||
String baseUrl,
|
||||
String appkey,
|
||||
String accessToken,
|
||||
Map<String, String> params,
|
||||
) {
|
||||
params.putIfAbsent('source', () => appkey);
|
||||
params.putIfAbsent('access_token', () => accessToken);
|
||||
|
||||
Uri baseUri = Uri.parse(baseUrl);
|
||||
Map<String, List<String>> queryParametersAll =
|
||||
Map<String, List<String>>.of(baseUri.queryParametersAll);
|
||||
params.forEach((String key, String value) {
|
||||
queryParametersAll.remove(key);
|
||||
queryParametersAll.putIfAbsent(key, () => <String>[value]);
|
||||
});
|
||||
|
||||
return baseUri.replace(queryParameters: queryParametersAll);
|
||||
}
|
||||
|
||||
Future<void> shareText({
|
||||
@required String text,
|
||||
}) {
|
||||
assert(text != null && text.isNotEmpty && text.length <= 1024);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHARETEXT,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_TEXT: text,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareImage({
|
||||
@required Uint8List imageData,
|
||||
}) {
|
||||
assert(imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHAREIMAGE,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_IMAGEDATA: imageData,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareWebpage({
|
||||
@required String title,
|
||||
@required String description,
|
||||
@required Uint8List thumbData,
|
||||
@required String webpageUrl,
|
||||
}) {
|
||||
assert(title != null && title.isNotEmpty && title.length <= 512);
|
||||
assert(description != null &&
|
||||
description.isNotEmpty &&
|
||||
description.length <= 1024);
|
||||
assert(thumbData != null && thumbData.lengthInBytes <= 32 * 1024);
|
||||
assert(webpageUrl != null &&
|
||||
webpageUrl.isNotEmpty &&
|
||||
webpageUrl.length <= 255);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHAREWEBPAGE,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_TITLE: title,
|
||||
_ARGUMENT_KEY_DESCRIPTION: description,
|
||||
_ARGUMENT_KEY_THUMBDATA: thumbData,
|
||||
_ARGUMENT_KEY_WEBPAGEURL: webpageUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class FakeWeiboProvider extends InheritedWidget {
|
||||
FakeWeiboProvider({
|
||||
Key key,
|
||||
@required this.weibo,
|
||||
@required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
final FakeWeibo weibo;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(InheritedWidget oldWidget) {
|
||||
FakeWeiboProvider oldProvider = oldWidget as FakeWeiboProvider;
|
||||
return weibo != oldProvider.weibo;
|
||||
}
|
||||
|
||||
static FakeWeiboProvider of(BuildContext context) {
|
||||
return context.inheritFromWidgetOfExactType(FakeWeiboProvider)
|
||||
as FakeWeiboProvider;
|
||||
}
|
||||
}
|
||||
library fake_weibo;
|
||||
|
||||
export 'src/domain/api/weibo_api_resp.dart';
|
||||
export 'src/domain/api/weibo_user_info_resp.dart'
|
||||
hide WeiboUserInfoRespSerializer;
|
||||
export 'src/domain/sdk/weibo_auth_resp.dart' hide WeiboAuthRespSerializer;
|
||||
export 'src/domain/sdk/weibo_sdk_resp.dart' hide WeiboSdkRespSerializer;
|
||||
export 'src/weibo.dart';
|
||||
export 'src/weibo_scope.dart';
|
||||
|
14
lib/src/domain/api/weibo_api_resp.dart
Normal file
14
lib/src/domain/api/weibo_api_resp.dart
Normal file
@ -0,0 +1,14 @@
|
||||
abstract class WeiboApiResp {
|
||||
WeiboApiResp({
|
||||
int errorCode,
|
||||
this.error,
|
||||
this.request,
|
||||
}) : errorCode = errorCode ?? ERROR_CODE_SUCCESS;
|
||||
|
||||
static const int ERROR_CODE_SUCCESS = 0;
|
||||
|
||||
/// https://open.weibo.com/wiki/Help/error
|
||||
final int errorCode;
|
||||
final String error;
|
||||
final String request;
|
||||
}
|
64
lib/src/domain/api/weibo_user_info_resp.dart
Normal file
64
lib/src/domain/api/weibo_user_info_resp.dart
Normal file
@ -0,0 +1,64 @@
|
||||
import 'package:jaguar_serializer/jaguar_serializer.dart';
|
||||
import 'package:fake_weibo/src/domain/api/weibo_api_resp.dart';
|
||||
|
||||
part 'weibo_user_info_resp.jser.dart';
|
||||
|
||||
@GenSerializer(nameFormatter: toSnakeCase)
|
||||
class WeiboUserInfoRespSerializer extends Serializer<WeiboUserInfoResp>
|
||||
with _$WeiboUserInfoRespSerializer {}
|
||||
|
||||
class WeiboUserInfoResp extends WeiboApiResp {
|
||||
WeiboUserInfoResp({
|
||||
int errorCode,
|
||||
String error,
|
||||
String request,
|
||||
this.id,
|
||||
this.idstr,
|
||||
this.screenName,
|
||||
this.name,
|
||||
this.location,
|
||||
this.description,
|
||||
this.profileImageUrl,
|
||||
this.gender,
|
||||
this.avatarLarge,
|
||||
this.avatarHd,
|
||||
}) : super(errorCode: errorCode, error: error, request: request);
|
||||
|
||||
/// 用户UID(int64)
|
||||
final int id;
|
||||
|
||||
/// 字符串型的用户 UID
|
||||
final String idstr;
|
||||
|
||||
/// 用户昵称
|
||||
final String screenName;
|
||||
|
||||
/// 友好显示名称
|
||||
final String name;
|
||||
|
||||
/// 用户所在地
|
||||
final String location;
|
||||
|
||||
/// 用户个人描述
|
||||
final String description;
|
||||
|
||||
/// 用户头像地址,50×50像素
|
||||
final String profileImageUrl;
|
||||
|
||||
/// 性别,m:男、f:女、n:未知
|
||||
final String gender;
|
||||
|
||||
/// 用户大头像地址
|
||||
final String avatarLarge;
|
||||
|
||||
/// 用户高清大头像地址
|
||||
final String avatarHd;
|
||||
|
||||
bool isMale() {
|
||||
return gender == 'm';
|
||||
}
|
||||
|
||||
bool isFemale() {
|
||||
return gender == 'f';
|
||||
}
|
||||
}
|
54
lib/src/domain/api/weibo_user_info_resp.jser.dart
Normal file
54
lib/src/domain/api/weibo_user_info_resp.jser.dart
Normal file
@ -0,0 +1,54 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weibo_user_info_resp.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JaguarSerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class _$WeiboUserInfoRespSerializer
|
||||
implements Serializer<WeiboUserInfoResp> {
|
||||
@override
|
||||
Map<String, dynamic> toMap(WeiboUserInfoResp model) {
|
||||
if (model == null) return null;
|
||||
Map<String, dynamic> ret = <String, dynamic>{};
|
||||
setMapValue(ret, 'id', model.id);
|
||||
setMapValue(ret, 'idstr', model.idstr);
|
||||
setMapValue(ret, 'screen_name', model.screenName);
|
||||
setMapValue(ret, 'name', model.name);
|
||||
setMapValue(ret, 'location', model.location);
|
||||
setMapValue(ret, 'description', model.description);
|
||||
setMapValue(ret, 'profile_image_url', model.profileImageUrl);
|
||||
setMapValue(ret, 'gender', model.gender);
|
||||
setMapValue(ret, 'avatar_large', model.avatarLarge);
|
||||
setMapValue(ret, 'avatar_hd', model.avatarHd);
|
||||
setMapValue(ret, 'error_code', model.errorCode);
|
||||
setMapValue(ret, 'error', model.error);
|
||||
setMapValue(ret, 'request', model.request);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@override
|
||||
WeiboUserInfoResp fromMap(Map map) {
|
||||
if (map == null) return null;
|
||||
final obj = new WeiboUserInfoResp(
|
||||
errorCode: map['error_code'] as int ?? getJserDefault('errorCode'),
|
||||
error: map['error'] as String ?? getJserDefault('error'),
|
||||
request: map['request'] as String ?? getJserDefault('request'),
|
||||
id: map['id'] as int ?? getJserDefault('id'),
|
||||
idstr: map['idstr'] as String ?? getJserDefault('idstr'),
|
||||
screenName:
|
||||
map['screen_name'] as String ?? getJserDefault('screenName'),
|
||||
name: map['name'] as String ?? getJserDefault('name'),
|
||||
location: map['location'] as String ?? getJserDefault('location'),
|
||||
description:
|
||||
map['description'] as String ?? getJserDefault('description'),
|
||||
profileImageUrl: map['profile_image_url'] as String ??
|
||||
getJserDefault('profileImageUrl'),
|
||||
gender: map['gender'] as String ?? getJserDefault('gender'),
|
||||
avatarLarge:
|
||||
map['avatar_large'] as String ?? getJserDefault('avatarLarge'),
|
||||
avatarHd: map['avatar_hd'] as String ?? getJserDefault('avatarHd'));
|
||||
return obj;
|
||||
}
|
||||
}
|
24
lib/src/domain/sdk/weibo_auth_resp.dart
Normal file
24
lib/src/domain/sdk/weibo_auth_resp.dart
Normal file
@ -0,0 +1,24 @@
|
||||
import 'package:jaguar_serializer/jaguar_serializer.dart';
|
||||
import 'package:fake_weibo/src/domain/sdk/weibo_sdk_resp.dart';
|
||||
|
||||
part 'weibo_auth_resp.jser.dart';
|
||||
|
||||
@GenSerializer()
|
||||
class WeiboAuthRespSerializer extends Serializer<WeiboAuthResp>
|
||||
with _$WeiboAuthRespSerializer {}
|
||||
|
||||
class WeiboAuthResp extends WeiboSdkResp {
|
||||
WeiboAuthResp({
|
||||
int errorCode,
|
||||
String errorMessage,
|
||||
this.userId,
|
||||
this.accessToken,
|
||||
this.refreshToken,
|
||||
this.expiresIn,
|
||||
}) : super(errorCode: errorCode, errorMessage: errorMessage);
|
||||
|
||||
final String userId;
|
||||
final String accessToken;
|
||||
final String refreshToken;
|
||||
final int expiresIn;
|
||||
}
|
38
lib/src/domain/sdk/weibo_auth_resp.jser.dart
Normal file
38
lib/src/domain/sdk/weibo_auth_resp.jser.dart
Normal file
@ -0,0 +1,38 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weibo_auth_resp.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JaguarSerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class _$WeiboAuthRespSerializer implements Serializer<WeiboAuthResp> {
|
||||
@override
|
||||
Map<String, dynamic> toMap(WeiboAuthResp model) {
|
||||
if (model == null) return null;
|
||||
Map<String, dynamic> ret = <String, dynamic>{};
|
||||
setMapValue(ret, 'userId', model.userId);
|
||||
setMapValue(ret, 'accessToken', model.accessToken);
|
||||
setMapValue(ret, 'refreshToken', model.refreshToken);
|
||||
setMapValue(ret, 'expiresIn', model.expiresIn);
|
||||
setMapValue(ret, 'errorCode', model.errorCode);
|
||||
setMapValue(ret, 'errorMessage', model.errorMessage);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@override
|
||||
WeiboAuthResp fromMap(Map map) {
|
||||
if (map == null) return null;
|
||||
final obj = new WeiboAuthResp(
|
||||
errorCode: map['errorCode'] as int ?? getJserDefault('errorCode'),
|
||||
errorMessage:
|
||||
map['errorMessage'] as String ?? getJserDefault('errorMessage'),
|
||||
userId: map['userId'] as String ?? getJserDefault('userId'),
|
||||
accessToken:
|
||||
map['accessToken'] as String ?? getJserDefault('accessToken'),
|
||||
refreshToken:
|
||||
map['refreshToken'] as String ?? getJserDefault('refreshToken'),
|
||||
expiresIn: map['expiresIn'] as int ?? getJserDefault('expiresIn'));
|
||||
return obj;
|
||||
}
|
||||
}
|
47
lib/src/domain/sdk/weibo_sdk_resp.dart
Normal file
47
lib/src/domain/sdk/weibo_sdk_resp.dart
Normal file
@ -0,0 +1,47 @@
|
||||
import 'package:jaguar_serializer/jaguar_serializer.dart';
|
||||
|
||||
part 'weibo_sdk_resp.jser.dart';
|
||||
|
||||
@GenSerializer()
|
||||
class WeiboSdkRespSerializer extends Serializer<WeiboSdkResp>
|
||||
with _$WeiboSdkRespSerializer {}
|
||||
|
||||
class WeiboSdkResp {
|
||||
WeiboSdkResp({
|
||||
int errorCode,
|
||||
this.errorMessage,
|
||||
}) : errorCode = errorCode ?? SUCCESS;
|
||||
|
||||
/// 成功
|
||||
static const int SUCCESS = 0;
|
||||
|
||||
/// 用户取消发送
|
||||
static const int USERCANCEL = -1;
|
||||
|
||||
/// 发送失败
|
||||
static const int SENT_FAIL = -2;
|
||||
|
||||
/// 授权失败
|
||||
static const int AUTH_DENY = -3;
|
||||
|
||||
/// 用户取消安装微博客户端
|
||||
static const int USERCANCEL_INSTALL = -4;
|
||||
|
||||
/// 支付失败
|
||||
static const int PAY_FAIL = -5;
|
||||
|
||||
/// 分享失败 详情见response UserInfo
|
||||
static const int SHARE_IN_SDK_FAILED = -8;
|
||||
|
||||
/// 不支持的请求
|
||||
static const int UNSUPPORT = -99;
|
||||
|
||||
/// 未知
|
||||
static const int UNKNOWN = -100;
|
||||
|
||||
/// sso package or sign error
|
||||
static const int SSO_PKG_SIGN_ERROR = 21338;
|
||||
|
||||
final int errorCode;
|
||||
final String errorMessage;
|
||||
}
|
28
lib/src/domain/sdk/weibo_sdk_resp.jser.dart
Normal file
28
lib/src/domain/sdk/weibo_sdk_resp.jser.dart
Normal file
@ -0,0 +1,28 @@
|
||||
// GENERATED CODE - DO NOT MODIFY BY HAND
|
||||
|
||||
part of 'weibo_sdk_resp.dart';
|
||||
|
||||
// **************************************************************************
|
||||
// JaguarSerializerGenerator
|
||||
// **************************************************************************
|
||||
|
||||
abstract class _$WeiboSdkRespSerializer implements Serializer<WeiboSdkResp> {
|
||||
@override
|
||||
Map<String, dynamic> toMap(WeiboSdkResp model) {
|
||||
if (model == null) return null;
|
||||
Map<String, dynamic> ret = <String, dynamic>{};
|
||||
setMapValue(ret, 'errorCode', model.errorCode);
|
||||
setMapValue(ret, 'errorMessage', model.errorMessage);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@override
|
||||
WeiboSdkResp fromMap(Map map) {
|
||||
if (map == null) return null;
|
||||
final obj = new WeiboSdkResp(
|
||||
errorCode: map['errorCode'] as int ?? getJserDefault('errorCode'),
|
||||
errorMessage:
|
||||
map['errorMessage'] as String ?? getJserDefault('errorMessage'));
|
||||
return obj;
|
||||
}
|
||||
}
|
221
lib/src/weibo.dart
Normal file
221
lib/src/weibo.dart
Normal file
@ -0,0 +1,221 @@
|
||||
import 'dart:async';
|
||||
import 'dart:convert';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:fake_weibo/src/domain/api/weibo_user_info_resp.dart';
|
||||
import 'package:fake_weibo/src/domain/sdk/weibo_auth_resp.dart';
|
||||
import 'package:fake_weibo/src/domain/sdk/weibo_sdk_resp.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
import 'package:meta/meta.dart';
|
||||
|
||||
class Weibo {
|
||||
static const String _METHOD_REGISTERAPP = 'registerApp';
|
||||
static const String _METHOD_ISWEIBOINSTALLED = 'isWeiboInstalled';
|
||||
static const String _METHOD_AUTH = 'auth';
|
||||
static const String _METHOD_SHARETEXT = 'shareText';
|
||||
static const String _METHOD_SHAREIMAGE = 'shareImage';
|
||||
static const String _METHOD_SHAREWEBPAGE = 'shareWebpage';
|
||||
|
||||
static const String _METHOD_ONAUTHRESP = 'onAuthResp';
|
||||
static const String _METHOD_ONSHAREMSGRESP = 'onShareMsgResp';
|
||||
|
||||
static const String _ARGUMENT_KEY_APPKEY = 'appKey';
|
||||
static const String _ARGUMENT_KEY_SCOPE = 'scope';
|
||||
static const String _ARGUMENT_KEY_REDIRECTURL = 'redirectUrl';
|
||||
static const String _ARGUMENT_KEY_TEXT = 'text';
|
||||
static const String _ARGUMENT_KEY_TITLE = 'title';
|
||||
static const String _ARGUMENT_KEY_DESCRIPTION = 'description';
|
||||
static const String _ARGUMENT_KEY_THUMBDATA = 'thumbData';
|
||||
static const String _ARGUMENT_KEY_IMAGEDATA = 'imageData';
|
||||
static const String _ARGUMENT_KEY_WEBPAGEURL = 'webpageUrl';
|
||||
|
||||
static const String _DEFAULT_REDIRECTURL =
|
||||
'https://api.weibo.com/oauth2/default.html';
|
||||
|
||||
static const MethodChannel _channel =
|
||||
MethodChannel('v7lin.github.io/fake_weibo');
|
||||
|
||||
final StreamController<WeiboAuthResp> _authRespStreamController =
|
||||
StreamController<WeiboAuthResp>.broadcast();
|
||||
|
||||
final StreamController<WeiboSdkResp> _shareMsgRespStreamController =
|
||||
StreamController<WeiboSdkResp>.broadcast();
|
||||
|
||||
Future<void> registerApp({
|
||||
@required String appKey,
|
||||
@required List<String> scope,
|
||||
String redirectUrl =
|
||||
_DEFAULT_REDIRECTURL, // 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置
|
||||
}) {
|
||||
assert(appKey != null && appKey.isNotEmpty);
|
||||
assert(scope != null && scope.isNotEmpty);
|
||||
_channel.setMethodCallHandler(_handleMethod);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_REGISTERAPP,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_APPKEY: appKey,
|
||||
_ARGUMENT_KEY_SCOPE: scope.join(','),
|
||||
_ARGUMENT_KEY_REDIRECTURL: redirectUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<dynamic> _handleMethod(MethodCall call) async {
|
||||
switch (call.method) {
|
||||
case _METHOD_ONAUTHRESP:
|
||||
_authRespStreamController.add(WeiboAuthRespSerializer()
|
||||
.fromMap(call.arguments as Map<dynamic, dynamic>));
|
||||
break;
|
||||
case _METHOD_ONSHAREMSGRESP:
|
||||
_shareMsgRespStreamController.add(WeiboSdkRespSerializer()
|
||||
.fromMap(call.arguments as Map<dynamic, dynamic>));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
Stream<WeiboAuthResp> authResp() {
|
||||
return _authRespStreamController.stream;
|
||||
}
|
||||
|
||||
Stream<WeiboSdkResp> shareMsgResp() {
|
||||
return _shareMsgRespStreamController.stream;
|
||||
}
|
||||
|
||||
Future<bool> isWeiboInstalled() async {
|
||||
return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool;
|
||||
}
|
||||
|
||||
Future<void> auth({
|
||||
@required String appKey,
|
||||
@required List<String> scope,
|
||||
String redirectUrl = _DEFAULT_REDIRECTURL,
|
||||
}) {
|
||||
assert(appKey != null && appKey.isNotEmpty);
|
||||
assert(scope != null && scope.isNotEmpty);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_AUTH,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_APPKEY: appKey,
|
||||
_ARGUMENT_KEY_SCOPE: scope.join(','),
|
||||
_ARGUMENT_KEY_REDIRECTURL: redirectUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<WeiboUserInfoResp> getUserInfo({
|
||||
@required String appkey,
|
||||
@required String userId,
|
||||
@required String accessToken,
|
||||
}) {
|
||||
assert(userId != null && userId.isNotEmpty);
|
||||
assert(accessToken != null && accessToken.isNotEmpty);
|
||||
Map<String, String> params = <String, String>{
|
||||
'uid': userId,
|
||||
};
|
||||
return HttpClient()
|
||||
.getUrl(_encodeUrl('https://api.weibo.com/2/users/show.json', appkey,
|
||||
accessToken, params))
|
||||
.then((HttpClientRequest request) {
|
||||
return request.close();
|
||||
}).then((HttpClientResponse response) async {
|
||||
if (response.statusCode == HttpStatus.ok) {
|
||||
String content = await utf8.decodeStream(response);
|
||||
return WeiboUserInfoRespSerializer()
|
||||
.fromMap(json.decode(content) as Map<dynamic, dynamic>);
|
||||
}
|
||||
throw HttpException(
|
||||
'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.');
|
||||
});
|
||||
}
|
||||
|
||||
Uri _encodeUrl(
|
||||
String baseUrl,
|
||||
String appkey,
|
||||
String accessToken,
|
||||
Map<String, String> params,
|
||||
) {
|
||||
params.putIfAbsent('source', () => appkey);
|
||||
params.putIfAbsent('access_token', () => accessToken);
|
||||
|
||||
Uri baseUri = Uri.parse(baseUrl);
|
||||
Map<String, List<String>> queryParametersAll =
|
||||
Map<String, List<String>>.of(baseUri.queryParametersAll);
|
||||
params.forEach((String key, String value) {
|
||||
queryParametersAll.remove(key);
|
||||
queryParametersAll.putIfAbsent(key, () => <String>[value]);
|
||||
});
|
||||
|
||||
return baseUri.replace(queryParameters: queryParametersAll);
|
||||
}
|
||||
|
||||
Future<void> shareText({
|
||||
@required String text,
|
||||
}) {
|
||||
assert(text != null && text.isNotEmpty && text.length <= 1024);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHARETEXT,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_TEXT: text,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareImage({
|
||||
@required Uint8List imageData,
|
||||
}) {
|
||||
assert(imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHAREIMAGE,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_IMAGEDATA: imageData,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> shareWebpage({
|
||||
@required String title,
|
||||
@required String description,
|
||||
@required Uint8List thumbData,
|
||||
@required String webpageUrl,
|
||||
}) {
|
||||
assert(title != null && title.isNotEmpty && title.length <= 512);
|
||||
assert(description != null &&
|
||||
description.isNotEmpty &&
|
||||
description.length <= 1024);
|
||||
assert(thumbData != null && thumbData.lengthInBytes <= 32 * 1024);
|
||||
assert(webpageUrl != null &&
|
||||
webpageUrl.isNotEmpty &&
|
||||
webpageUrl.length <= 255);
|
||||
return _channel.invokeMethod(
|
||||
_METHOD_SHAREWEBPAGE,
|
||||
<String, dynamic>{
|
||||
_ARGUMENT_KEY_TITLE: title,
|
||||
_ARGUMENT_KEY_DESCRIPTION: description,
|
||||
_ARGUMENT_KEY_THUMBDATA: thumbData,
|
||||
_ARGUMENT_KEY_WEBPAGEURL: webpageUrl,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class WeiboProvider extends InheritedWidget {
|
||||
WeiboProvider({
|
||||
Key key,
|
||||
@required this.weibo,
|
||||
@required Widget child,
|
||||
}) : super(key: key, child: child);
|
||||
|
||||
final Weibo weibo;
|
||||
|
||||
@override
|
||||
bool updateShouldNotify(InheritedWidget oldWidget) {
|
||||
WeiboProvider oldProvider = oldWidget as WeiboProvider;
|
||||
return weibo != oldProvider.weibo;
|
||||
}
|
||||
|
||||
static WeiboProvider of(BuildContext context) {
|
||||
return context.inheritFromWidgetOfExactType(WeiboProvider) as WeiboProvider;
|
||||
}
|
||||
}
|
14
lib/src/weibo_scope.dart
Normal file
14
lib/src/weibo_scope.dart
Normal file
@ -0,0 +1,14 @@
|
||||
class WeiboScope {
|
||||
WeiboScope._();
|
||||
|
||||
static const String EMAIL = 'email';
|
||||
static const String DIRECT_MESSAGES_READ = 'direct_messages_read';
|
||||
static const String DIRECT_MESSAGES_WRITE = 'direct_messages_write';
|
||||
static const String FRIENDSHIPS_GROUPS_READ = 'friendships_groups_read';
|
||||
static const String FRIENDSHIPS_GROUPS_WRITE = 'friendships_groups_write';
|
||||
static const String STATUSES_TO_ME_READ = 'statuses_to_me_read';
|
||||
static const String FOLLOW_APP_OFFICIAL_MICROBLOG =
|
||||
'follow_app_official_microblog';
|
||||
static const String INVITATION_WRITE = 'invitation_write';
|
||||
static const String ALL = 'all';
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
name: fake_weibo
|
||||
description: A powerful weibo plugin for Flutter.
|
||||
version: 0.0.1+1
|
||||
version: 0.1.0
|
||||
author: v7lin <v7lin@qq.com>
|
||||
homepage: https://github.com/v7lin/fake_weibo
|
||||
|
||||
|
@ -1,3 +1,7 @@
|
||||
import 'dart:convert';
|
||||
|
||||
import 'package:fake_weibo/src/domain/api/weibo_user_info_resp.dart';
|
||||
import 'package:fake_weibo/src/domain/sdk/weibo_auth_resp.dart';
|
||||
import 'package:flutter_test/flutter_test.dart';
|
||||
import 'package:jaguar_serializer/jaguar_serializer.dart';
|
||||
|
||||
@ -21,6 +25,19 @@ void main() {
|
||||
});
|
||||
|
||||
test('smoke test - jaguar_serializer', () {
|
||||
WeiboAuthResp authResp = WeiboAuthRespSerializer().fromMap(json.decode(
|
||||
'{"expiresIn":157679999,"errorCode":0,"accessToken":"2.00s67kHGj4SghD8e46233eea9O1IDB","userId":"5611295980","refreshToken":"2.00s67kHGj4SghD6ee52b48200iqHz3"}')
|
||||
as Map<dynamic, dynamic>);
|
||||
expect(authResp.errorCode, equals(0));
|
||||
expect(authResp.expiresIn, equals(157679999));
|
||||
expect(authResp.accessToken, equals('2.00s67kHGj4SghD8e46233eea9O1IDB'));
|
||||
|
||||
WeiboUserInfoResp userInfoResp = WeiboUserInfoRespSerializer().fromMap(json.decode(
|
||||
'{"id":5611295980,"idstr":"5611295980","class":1,"screen_name":"v7lin","name":"v7lin","province":"35","city":"1","location":"福建 福州","description":"","url":"","profile_image_url":"http://tvax4.sinaimg.cn/crop.0.0.640.640.50/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","cover_image_phone":"http://ww1.sinaimg.cn/crop.0.0.640.640.640/549d0121tw1egm1kjly3jj20hs0hsq4f.jpg","profile_url":"u/5611295980","domain":"","weihao":"","gender":"m","followers_count":1,"friends_count":1,"pagefriends_count":0,"statuses_count":0,"video_status_count":0,"favourites_count":0,"created_at":"Mon May 18 19:32:52 +0800 2015","following":false,"allow_all_act_msg":false,"geo_enabled":true,"verified":false,"verified_type":-1,"remark":"","insecurity":{"sexual_content":false},"ptype":0,"allow_all_comment":true,"avatar_large":"http://tvax4.sinaimg.cn/crop.0.0.640.640.180/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","avatar_hd":"http://tvax4.sinaimg.cn/crop.0.0.640.640.1024/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg","verified_reason":"","verified_trade":"","verified_reason_url":"","verified_source":"","verified_source_url":"","follow_me":false,"like":false,"like_me":false,"online_status":0,"bi_followers_count":0,"lang":"zh-cn","star":0,"mbtype":0,"mbrank":0,"block_word":0,"block_app":0,"credit_score":80,"user_ability":0,"urank":4,"story_read_state":-1,"vclub_member":0,"is_teenager":0,"is_guardian":0,"is_teenager_list":0}')
|
||||
as Map<dynamic, dynamic>);
|
||||
expect(userInfoResp.errorCode, equals(0));
|
||||
expect(userInfoResp.id, equals(5611295980));
|
||||
expect(userInfoResp.screenName, equals('v7lin'));
|
||||
expect(userInfoResp.avatarHd, equals('http://tvax4.sinaimg.cn/crop.0.0.640.640.1024/0067KqpSly8fujqh4oj39j30hs0hsjs6.jpg'));
|
||||
});
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user