From 59d1407e744a3635d2daef8fc80372db11926510 Mon Sep 17 00:00:00 2001 From: v7lin Date: Tue, 19 Mar 2019 19:06:18 +0800 Subject: [PATCH] fake_weibo 0.1.0 --- README.md | 2 +- .../v7lin/fakeweibo/FakeWeiboPlugin.java | 23 +- example/ios/Runner.xcodeproj/project.pbxproj | 4 - example/lib/main.dart | 54 +- ios/Classes/FakeWeiboPlugin.m | 6 +- lib/fake_weibo.dart | 538 +----------------- lib/src/domain/api/weibo_api_resp.dart | 14 + lib/src/domain/api/weibo_user_info_resp.dart | 64 +++ .../domain/api/weibo_user_info_resp.jser.dart | 54 ++ lib/src/domain/sdk/weibo_auth_resp.dart | 24 + lib/src/domain/sdk/weibo_auth_resp.jser.dart | 38 ++ lib/src/domain/sdk/weibo_sdk_resp.dart | 47 ++ lib/src/domain/sdk/weibo_sdk_resp.jser.dart | 28 + lib/src/weibo.dart | 221 +++++++ lib/src/weibo_scope.dart | 14 + pubspec.yaml | 2 +- test/jaguar_test.dart | 17 + 17 files changed, 576 insertions(+), 574 deletions(-) create mode 100644 lib/src/domain/api/weibo_api_resp.dart create mode 100644 lib/src/domain/api/weibo_user_info_resp.dart create mode 100644 lib/src/domain/api/weibo_user_info_resp.jser.dart create mode 100644 lib/src/domain/sdk/weibo_auth_resp.dart create mode 100644 lib/src/domain/sdk/weibo_auth_resp.jser.dart create mode 100644 lib/src/domain/sdk/weibo_sdk_resp.dart create mode 100644 lib/src/domain/sdk/weibo_sdk_resp.jser.dart create mode 100644 lib/src/weibo.dart create mode 100644 lib/src/weibo_scope.dart diff --git a/README.md b/README.md index f10a010..12a7c85 100644 --- a/README.md +++ b/README.md @@ -74,7 +74,7 @@ dependencies: ### release ```` -latestVersion = 0.0.1+1 +latestVersion = 0.1.0 ```` ```` diff --git a/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java b/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java index 79f2fb3..4e4a22d 100644 --- a/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java +++ b/android/src/main/java/io/github/v7lin/fakeweibo/FakeWeiboPlugin.java @@ -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 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 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 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 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 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 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 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); } }); diff --git a/example/ios/Runner.xcodeproj/project.pbxproj b/example/ios/Runner.xcodeproj/project.pbxproj index 9c665d8..b1fd172 100644 --- a/example/ios/Runner.xcodeproj/project.pbxproj +++ b/example/ios/Runner.xcodeproj/project.pbxproj @@ -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 = ""; }; 1498D2331E8E89220040F4C2 /* GeneratedPluginRegistrant.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GeneratedPluginRegistrant.m; sourceTree = ""; }; - 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 = ""; }; 3B80C3931E831B6300D905FE /* App.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = App.framework; path = Flutter/App.framework; sourceTree = ""; }; 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; @@ -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; diff --git a/example/lib/main.dart b/example/lib/main.dart index 9976fbd..1e44a6f 100644 --- a/example/lib/main.dart +++ b/example/lib/main.dart @@ -6,6 +6,9 @@ import 'package:flutter/services.dart'; import 'package:fake_weibo/fake_weibo.dart'; const String _WEIBO_APP_KEY = '3393861383'; +const List _WEIBO_SCOPE = [ + 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 createState() { @@ -55,10 +56,10 @@ class Home extends StatefulWidget { } class _HomeState extends State { - StreamSubscription _auth; - StreamSubscription _share; + StreamSubscription _auth; + StreamSubscription _share; - FakeWeiboAuthResp _authResp; + WeiboAuthResp _authResp; @override void initState() { @@ -67,13 +68,13 @@ class _HomeState extends State { _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 { 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}'); } } }, diff --git a/ios/Classes/FakeWeiboPlugin.m b/ios/Classes/FakeWeiboPlugin.m index 86c8075..bb34b43 100644 --- a/ios/Classes/FakeWeiboPlugin.m +++ b/ios/Classes/FakeWeiboPlugin.m @@ -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]]) { diff --git a/lib/fake_weibo.dart b/lib/fake_weibo.dart index fad4273..11879a6 100644 --- a/lib/fake_weibo.dart +++ b/lib/fake_weibo.dart @@ -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 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 _scope; - - /// 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置 - final String _redirectUrl; - - final StreamController _authRespStreamController = - StreamController.broadcast(); - - final StreamController _shareMsgRespStreamController = - StreamController.broadcast(); - - Future registerApp() { - _channel.setMethodCallHandler(_handleMethod); - return _channel.invokeMethod( - _METHOD_REGISTERAPP, - { - _ARGUMENT_KEY_APPKEY: _appKey, - _ARGUMENT_KEY_SCOPE: _scope.join(','), - _ARGUMENT_KEY_REDIRECTURL: _redirectUrl, - }, - ); - } - - Future _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 authResp() { - return _authRespStreamController.stream; - } - - Stream shareMsgResp() { - return _shareMsgRespStreamController.stream; - } - - Future isWeiboInstalled() async { - return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool; - } - - Future auth() { - return _channel.invokeMethod( - _METHOD_AUTH, - { - _ARGUMENT_KEY_APPKEY: _appKey, - _ARGUMENT_KEY_SCOPE: _scope.join(','), - _ARGUMENT_KEY_REDIRECTURL: _redirectUrl, - }, - ); - } - - Future getUserInfo({ - @required String appkey, - @required String userId, - @required String accessToken, - }) { - assert(userId != null && userId.isNotEmpty); - assert(accessToken != null && accessToken.isNotEmpty); - Map params = { - '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 map = json.decode(content) as Map; - 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 params, - ) { - params.putIfAbsent('source', () => appkey); - params.putIfAbsent('access_token', () => accessToken); - - Uri baseUri = Uri.parse(baseUrl); - Map> queryParametersAll = - Map>.of(baseUri.queryParametersAll); - params.forEach((String key, String value) { - queryParametersAll.remove(key); - queryParametersAll.putIfAbsent(key, () => [value]); - }); - - return baseUri.replace(queryParameters: queryParametersAll); - } - - Future shareText({ - @required String text, - }) { - assert(text != null && text.isNotEmpty && text.length <= 1024); - return _channel.invokeMethod( - _METHOD_SHARETEXT, - { - _ARGUMENT_KEY_TEXT: text, - }, - ); - } - - Future shareImage({ - @required Uint8List imageData, - }) { - assert(imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024); - return _channel.invokeMethod( - _METHOD_SHAREIMAGE, - { - _ARGUMENT_KEY_IMAGEDATA: imageData, - }, - ); - } - - Future 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, - { - _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'; diff --git a/lib/src/domain/api/weibo_api_resp.dart b/lib/src/domain/api/weibo_api_resp.dart new file mode 100644 index 0000000..349bd10 --- /dev/null +++ b/lib/src/domain/api/weibo_api_resp.dart @@ -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; +} diff --git a/lib/src/domain/api/weibo_user_info_resp.dart b/lib/src/domain/api/weibo_user_info_resp.dart new file mode 100644 index 0000000..8b84b25 --- /dev/null +++ b/lib/src/domain/api/weibo_user_info_resp.dart @@ -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 + 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'; + } +} diff --git a/lib/src/domain/api/weibo_user_info_resp.jser.dart b/lib/src/domain/api/weibo_user_info_resp.jser.dart new file mode 100644 index 0000000..caf32d7 --- /dev/null +++ b/lib/src/domain/api/weibo_user_info_resp.jser.dart @@ -0,0 +1,54 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_user_info_resp.dart'; + +// ************************************************************************** +// JaguarSerializerGenerator +// ************************************************************************** + +abstract class _$WeiboUserInfoRespSerializer + implements Serializer { + @override + Map toMap(WeiboUserInfoResp model) { + if (model == null) return null; + Map ret = {}; + 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; + } +} diff --git a/lib/src/domain/sdk/weibo_auth_resp.dart b/lib/src/domain/sdk/weibo_auth_resp.dart new file mode 100644 index 0000000..8724dd8 --- /dev/null +++ b/lib/src/domain/sdk/weibo_auth_resp.dart @@ -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 + 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; +} diff --git a/lib/src/domain/sdk/weibo_auth_resp.jser.dart b/lib/src/domain/sdk/weibo_auth_resp.jser.dart new file mode 100644 index 0000000..ab16ef5 --- /dev/null +++ b/lib/src/domain/sdk/weibo_auth_resp.jser.dart @@ -0,0 +1,38 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_auth_resp.dart'; + +// ************************************************************************** +// JaguarSerializerGenerator +// ************************************************************************** + +abstract class _$WeiboAuthRespSerializer implements Serializer { + @override + Map toMap(WeiboAuthResp model) { + if (model == null) return null; + Map ret = {}; + 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; + } +} diff --git a/lib/src/domain/sdk/weibo_sdk_resp.dart b/lib/src/domain/sdk/weibo_sdk_resp.dart new file mode 100644 index 0000000..9528b9e --- /dev/null +++ b/lib/src/domain/sdk/weibo_sdk_resp.dart @@ -0,0 +1,47 @@ +import 'package:jaguar_serializer/jaguar_serializer.dart'; + +part 'weibo_sdk_resp.jser.dart'; + +@GenSerializer() +class WeiboSdkRespSerializer extends Serializer + 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; +} diff --git a/lib/src/domain/sdk/weibo_sdk_resp.jser.dart b/lib/src/domain/sdk/weibo_sdk_resp.jser.dart new file mode 100644 index 0000000..2196011 --- /dev/null +++ b/lib/src/domain/sdk/weibo_sdk_resp.jser.dart @@ -0,0 +1,28 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'weibo_sdk_resp.dart'; + +// ************************************************************************** +// JaguarSerializerGenerator +// ************************************************************************** + +abstract class _$WeiboSdkRespSerializer implements Serializer { + @override + Map toMap(WeiboSdkResp model) { + if (model == null) return null; + Map ret = {}; + 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; + } +} diff --git a/lib/src/weibo.dart b/lib/src/weibo.dart new file mode 100644 index 0000000..26e56d6 --- /dev/null +++ b/lib/src/weibo.dart @@ -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 _authRespStreamController = + StreamController.broadcast(); + + final StreamController _shareMsgRespStreamController = + StreamController.broadcast(); + + Future registerApp({ + @required String appKey, + @required List 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, + { + _ARGUMENT_KEY_APPKEY: appKey, + _ARGUMENT_KEY_SCOPE: scope.join(','), + _ARGUMENT_KEY_REDIRECTURL: redirectUrl, + }, + ); + } + + Future _handleMethod(MethodCall call) async { + switch (call.method) { + case _METHOD_ONAUTHRESP: + _authRespStreamController.add(WeiboAuthRespSerializer() + .fromMap(call.arguments as Map)); + break; + case _METHOD_ONSHAREMSGRESP: + _shareMsgRespStreamController.add(WeiboSdkRespSerializer() + .fromMap(call.arguments as Map)); + break; + } + } + + Stream authResp() { + return _authRespStreamController.stream; + } + + Stream shareMsgResp() { + return _shareMsgRespStreamController.stream; + } + + Future isWeiboInstalled() async { + return (await _channel.invokeMethod(_METHOD_ISWEIBOINSTALLED)) as bool; + } + + Future auth({ + @required String appKey, + @required List scope, + String redirectUrl = _DEFAULT_REDIRECTURL, + }) { + assert(appKey != null && appKey.isNotEmpty); + assert(scope != null && scope.isNotEmpty); + return _channel.invokeMethod( + _METHOD_AUTH, + { + _ARGUMENT_KEY_APPKEY: appKey, + _ARGUMENT_KEY_SCOPE: scope.join(','), + _ARGUMENT_KEY_REDIRECTURL: redirectUrl, + }, + ); + } + + Future getUserInfo({ + @required String appkey, + @required String userId, + @required String accessToken, + }) { + assert(userId != null && userId.isNotEmpty); + assert(accessToken != null && accessToken.isNotEmpty); + Map params = { + '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); + } + throw HttpException( + 'HttpResponse statusCode: ${response.statusCode}, reasonPhrase: ${response.reasonPhrase}.'); + }); + } + + Uri _encodeUrl( + String baseUrl, + String appkey, + String accessToken, + Map params, + ) { + params.putIfAbsent('source', () => appkey); + params.putIfAbsent('access_token', () => accessToken); + + Uri baseUri = Uri.parse(baseUrl); + Map> queryParametersAll = + Map>.of(baseUri.queryParametersAll); + params.forEach((String key, String value) { + queryParametersAll.remove(key); + queryParametersAll.putIfAbsent(key, () => [value]); + }); + + return baseUri.replace(queryParameters: queryParametersAll); + } + + Future shareText({ + @required String text, + }) { + assert(text != null && text.isNotEmpty && text.length <= 1024); + return _channel.invokeMethod( + _METHOD_SHARETEXT, + { + _ARGUMENT_KEY_TEXT: text, + }, + ); + } + + Future shareImage({ + @required Uint8List imageData, + }) { + assert(imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024); + return _channel.invokeMethod( + _METHOD_SHAREIMAGE, + { + _ARGUMENT_KEY_IMAGEDATA: imageData, + }, + ); + } + + Future 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, + { + _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; + } +} diff --git a/lib/src/weibo_scope.dart b/lib/src/weibo_scope.dart new file mode 100644 index 0000000..b655c04 --- /dev/null +++ b/lib/src/weibo_scope.dart @@ -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'; +} diff --git a/pubspec.yaml b/pubspec.yaml index 2440581..e1714a6 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -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 homepage: https://github.com/v7lin/fake_weibo diff --git a/test/jaguar_test.dart b/test/jaguar_test.dart index ab1e2bc..ba8fbf9 100644 --- a/test/jaguar_test.dart +++ b/test/jaguar_test.dart @@ -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); + 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); + 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')); }); }