diff --git a/android/build.gradle b/android/build.gradle index ab0ef9b..182fcb9 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -56,7 +56,6 @@ android { } dependencies { - // v10.10.0 vendorImplementation 'androidx.appcompat:appcompat:1.0.0' - vendorImplementation 'io.github.sinaweibosdk:core:11.12.0@aar' + vendorImplementation 'io.github.sinaweibosdk:core:12.5.0@aar' } diff --git a/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java index 059fdd8..fd38486 100644 --- a/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java +++ b/android/src/main/java/io/github/v7lin/weibo_kit/WeiboKitPlugin.java @@ -14,6 +14,7 @@ import androidx.annotation.Nullable; import com.sina.weibo.sdk.api.ImageObject; import com.sina.weibo.sdk.api.MultiImageObject; import com.sina.weibo.sdk.api.TextObject; +import com.sina.weibo.sdk.api.VideoSourceObject; import com.sina.weibo.sdk.api.WebpageObject; import com.sina.weibo.sdk.api.WeiboMultiMessage; import com.sina.weibo.sdk.auth.AuthInfo; @@ -27,7 +28,9 @@ import com.sina.weibo.sdk.share.WbShareCallback; import java.io.File; import java.util.ArrayList; +import java.util.Arrays; import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.UUID; @@ -164,91 +167,105 @@ public class WeiboKitPlugin implements FlutterPlugin, ActivityAware, PluginRegis iwbapi.registerApp(applicationContext, new AuthInfo(applicationContext, appKey, redirectUrl, scope)); result.success(null); } else if ("isInstalled".equals(call.method)) { - result.success(iwbapi.isWBAppInstalled()); + if (iwbapi != null) { + result.success(iwbapi.isWBAppInstalled()); + } else { + result.error("FAILED", "请先调用registerApp", null); + } + } else if ("isSupportMultipleImage".equals(call.method)) { + if (iwbapi != null) { + result.success(iwbapi.isWBAppSupportMultipleImage()); + } else { + result.error("FAILED", "请先调用registerApp", null); + } } else if ("auth".equals(call.method)) { - handleAuthCall(call, result); - } else if ("shareText".equals(call.method)) { - handleShareTextCall(call, result); - } else if ("shareImage".equals(call.method) || - "shareWebpage".equals(call.method)) { - handleShareMediaCall(call, result); + if (iwbapi != null) { + handleAuthCall(call, result); + } else { + result.error("FAILED", "请先调用registerApp", null); + } + } else if (Arrays.asList("shareText", "shareImage", "shareMultiImage", "shareVideo", "shareWebpage").contains(call.method)) { + if (iwbapi != null) { + handleShareCall(call, result); + } else { + result.error("FAILED", "请先调用registerApp", null); + } } else { result.notImplemented(); } } private void handleAuthCall(@NonNull MethodCall call, @NonNull Result result) { - if (iwbapi != null) { - iwbapi.authorize(activityPluginBinding.getActivity(), new WbAuthListener() { - @Override - public void onComplete(Oauth2AccessToken token) { - final Map map = new HashMap<>(); - if (token.isSessionValid()) { - map.put("errorCode", WeiboErrorCode.SUCCESS); - map.put("userId", token.getUid()); - map.put("accessToken", token.getAccessToken()); - map.put("refreshToken", token.getRefreshToken()); - final long expiresIn = (long) Math.ceil(token.getExpiresTime() / 1000.0); - map.put("expiresIn", expiresIn);// 向上取整 - } else { - map.put("errorCode", WeiboErrorCode.UNKNOWN); - } - if (channel != null) { - channel.invokeMethod("onAuthResp", map); - } - } - - @Override - public void onError(UiError uiError) { - final Map map = new HashMap<>(); + iwbapi.authorize(activityPluginBinding.getActivity(), new WbAuthListener() { + @Override + public void onComplete(Oauth2AccessToken token) { + final Map map = new HashMap<>(); + if (token.isSessionValid()) { + map.put("errorCode", WeiboErrorCode.SUCCESS); + map.put("userId", token.getUid()); + map.put("accessToken", token.getAccessToken()); + map.put("refreshToken", token.getRefreshToken()); + final long expiresIn = (long) Math.ceil(token.getExpiresTime() / 1000.0); + map.put("expiresIn", expiresIn);// 向上取整 + } else { map.put("errorCode", WeiboErrorCode.UNKNOWN); - if (channel != null) { - channel.invokeMethod("onAuthResp", map); - } } + if (channel != null) { + channel.invokeMethod("onAuthResp", map); + } + } - @Override - public void onCancel() { - final Map map = new HashMap<>(); - map.put("errorCode", WeiboErrorCode.USERCANCEL); - if (channel != null) { - channel.invokeMethod("onAuthResp", map); - } + @Override + public void onError(UiError uiError) { + final Map map = new HashMap<>(); + map.put("errorCode", WeiboErrorCode.UNKNOWN); + if (channel != null) { + channel.invokeMethod("onAuthResp", map); } - }); - } + } + + @Override + public void onCancel() { + final Map map = new HashMap<>(); + map.put("errorCode", WeiboErrorCode.USERCANCEL); + if (channel != null) { + channel.invokeMethod("onAuthResp", map); + } + } + }); result.success(null); } - private void handleShareTextCall(@NonNull MethodCall call, @NonNull Result result) { + private void handleShareCall(@NonNull MethodCall call, @NonNull Result result) { final WeiboMultiMessage message = new WeiboMultiMessage(); - - final TextObject object = new TextObject(); - object.text = call.argument("text");// 1024 - - message.textObject = object; - - if (iwbapi != null) { - iwbapi.shareMessage(activityPluginBinding.getActivity(), message, false); - } - result.success(null); - } - - private void handleShareMediaCall(@NonNull MethodCall call, @NonNull Result result) { - final WeiboMultiMessage message = new WeiboMultiMessage(); - - if ("shareImage".equals(call.method)) { + if ("shareText".equals(call.method)) { + final TextObject object = new TextObject(); + object.text = call.argument("text");// 1024 + message.textObject = object; + } else if ("shareImage".equals(call.method)) { if (call.hasArgument("text")) { final TextObject object = new TextObject(); object.text = call.argument("text");// 1024 - message.textObject = object; } - - if (iwbapi != null && iwbapi.isWBAppSupportMultipleImage() && call.hasArgument("imageUri")) { - final MultiImageObject object = new MultiImageObject(); + final ImageObject object = new ImageObject(); + if (call.hasArgument("imageData")) { + object.imageData = call.argument("imageData");// 2 * 1024 * 1024 + } else if (call.hasArgument("imageUri")) { final String imageUri = call.argument("imageUri"); - final ArrayList images = new ArrayList<>(); + object.imagePath = Uri.parse(imageUri).getPath();// 512 - 10 * 1024 * 1024 + } + message.imageObject = object; + } else if ("shareMultiImage".equals(call.method)) { + if (call.hasArgument("text")) { + final TextObject object = new TextObject(); + object.text = call.argument("text");// 1024 + message.textObject = object; + } + final MultiImageObject object = new MultiImageObject(); + final List imageUris = call.argument("imageUris"); + final ArrayList images = new ArrayList<>(); + for (String imageUri : imageUris) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { try { final ProviderInfo providerInfo = applicationContext.getPackageManager().getProviderInfo(new ComponentName(applicationContext, FileProvider.class), PackageManager.MATCH_DEFAULT_ONLY); @@ -261,18 +278,30 @@ public class WeiboKitPlugin implements FlutterPlugin, ActivityAware, PluginRegis } else { images.add(Uri.parse(imageUri)); } - object.imageList = images; - message.mediaObject = object; - } else { - final ImageObject object = new ImageObject(); - if (call.hasArgument("imageData")) { - object.imageData = call.argument("imageData");// 2 * 1024 * 1024 - } else if (call.hasArgument("imageUri")) { - final String imageUri = call.argument("imageUri"); - object.imagePath = Uri.parse(imageUri).getPath();// 512 - 10 * 1024 * 1024 - } - message.mediaObject = object; } + object.imageList = images; + message.multiImageObject = object; + } else if ("shareVideo".equals(call.method)) { + if (call.hasArgument("text")) { + final TextObject object = new TextObject(); + object.text = call.argument("text");// 1024 + message.textObject = object; + } + final VideoSourceObject object = new VideoSourceObject(); + final String videoUri = call.argument("videoUri"); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { + try { + final ProviderInfo providerInfo = applicationContext.getPackageManager().getProviderInfo(new ComponentName(applicationContext, FileProvider.class), PackageManager.MATCH_DEFAULT_ONLY); + final Uri shareFileUri = FileProvider.getUriForFile(applicationContext, providerInfo.authority, new File(Uri.parse(videoUri).getPath())); + applicationContext.grantUriPermission("com.sina.weibo", shareFileUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); + object.videoPath = shareFileUri; + } catch (PackageManager.NameNotFoundException e) { + object.videoPath = Uri.parse(videoUri); + } + } else { + object.videoPath = Uri.parse(videoUri); + } + message.videoSourceObject = object; } else if ("shareWebpage".equals(call.method)) { final WebpageObject object = new WebpageObject(); object.identify = UUID.randomUUID().toString(); @@ -285,9 +314,9 @@ public class WeiboKitPlugin implements FlutterPlugin, ActivityAware, PluginRegis message.mediaObject = object; } - if (iwbapi != null) { - iwbapi.shareMessage(activityPluginBinding.getActivity(), message, false); - } + final boolean clientOnly = call.argument("clientOnly"); + + iwbapi.shareMessage(activityPluginBinding.getActivity(), message, clientOnly); result.success(null); } } diff --git a/example/pubspec.yaml b/example/pubspec.yaml index b0b921e..5ae4fb0 100644 --- a/example/pubspec.yaml +++ b/example/pubspec.yaml @@ -32,6 +32,8 @@ dependencies: # Use with the CupertinoIcons class for iOS style icons. cupertino_icons: ^1.0.2 + path: ^1.8.1 + path_provider: ^2.0.10 image: ^3.0.1 flutter_cache_manager: ^3.0.0 diff --git a/lib/src/weibo_kit_method_channel.dart b/lib/src/weibo_kit_method_channel.dart index 22019d9..c3ad252 100644 --- a/lib/src/weibo_kit_method_channel.dart +++ b/lib/src/weibo_kit_method_channel.dart @@ -12,21 +12,16 @@ import 'package:weibo_kit/src/weibo_kit_platform_interface.dart'; class MethodChannelWeiboKit extends WeiboKitPlatform { /// The method channel used to interact with the native platform. @visibleForTesting - late final MethodChannel methodChannel = - const MethodChannel('v7lin.github.io/weibo_kit') - ..setMethodCallHandler(_handleMethod); - final StreamController _respStreamController = - StreamController.broadcast(); + late final MethodChannel methodChannel = const MethodChannel('v7lin.github.io/weibo_kit')..setMethodCallHandler(_handleMethod); + final StreamController _respStreamController = StreamController.broadcast(); Future _handleMethod(MethodCall call) async { switch (call.method) { case 'onAuthResp': - _respStreamController.add(AuthResp.fromJson( - (call.arguments as Map).cast())); + _respStreamController.add(AuthResp.fromJson((call.arguments as Map).cast())); break; case 'onShareMsgResp': - _respStreamController.add(ShareMsgResp.fromJson( - (call.arguments as Map).cast())); + _respStreamController.add(ShareMsgResp.fromJson((call.arguments as Map).cast())); break; } } @@ -60,6 +55,11 @@ class MethodChannelWeiboKit extends WeiboKitPlatform { return await methodChannel.invokeMethod('isInstalled') ?? false; } + @override + Future isSupportMultipleImage() async { + return await methodChannel.invokeMethod('isSupportMultipleImage') ?? false; + } + @override Future auth({ required String appKey, @@ -79,11 +79,13 @@ class MethodChannelWeiboKit extends WeiboKitPlatform { @override Future shareText({ required String text, + bool clientOnly = false, }) { return methodChannel.invokeMethod( 'shareText', { 'text': text, + 'clientOnly': clientOnly, }, ); } @@ -93,19 +95,54 @@ class MethodChannelWeiboKit extends WeiboKitPlatform { String? text, Uint8List? imageData, Uri? imageUri, + bool clientOnly = false, }) { assert(text == null || text.length <= 1024); assert((imageData != null && imageData.lengthInBytes <= 2 * 1024 * 1024) || - (imageUri != null && - imageUri.isScheme('file') && - imageUri.toFilePath().length <= 512 && - File.fromUri(imageUri).lengthSync() <= 10 * 1024 * 1024)); + (imageUri != null && imageUri.isScheme('file') && imageUri.toFilePath().length <= 512 && File.fromUri(imageUri).lengthSync() <= 10 * 1024 * 1024)); return methodChannel.invokeMethod( 'shareImage', { if (text != null && text.isNotEmpty) 'text': text, if (imageData != null) 'imageData': imageData, if (imageUri != null) 'imageUri': imageUri.toString(), + 'clientOnly': clientOnly, + }, + ); + } + + @override + Future shareMultiImage({ + String? text, + required List imageUris, + bool clientOnly = false, + }) { + assert(text == null || text.length <= 1024); + assert(imageUris.isNotEmpty && imageUris.every((Uri element) => element.isScheme('file'))); + return methodChannel.invokeMethod( + 'shareMultiImage', + { + if (text != null && text.isNotEmpty) 'text': text, + 'imageUris': imageUris.map((Uri element) => element.toString()).toList(), + 'clientOnly': clientOnly, + }, + ); + } + + @override + Future shareVideo({ + String? text, + required Uri videoUri, + bool clientOnly = false, + }) { + assert(text == null || text.length <= 1024); + assert(videoUri.isScheme('file')); + return methodChannel.invokeMethod( + 'shareVideo', + { + if (text != null && text.isNotEmpty) 'text': text, + 'videoUri': videoUri.toString(), + 'clientOnly': clientOnly, }, ); } @@ -116,6 +153,7 @@ class MethodChannelWeiboKit extends WeiboKitPlatform { required String description, required Uint8List thumbData, required String webpageUrl, + bool clientOnly = false, }) { assert(title.length <= 512); assert(description.isNotEmpty && description.length <= 1024); @@ -128,6 +166,7 @@ class MethodChannelWeiboKit extends WeiboKitPlatform { 'description': description, 'thumbData': thumbData, 'webpageUrl': webpageUrl, + 'clientOnly': clientOnly, }, ); } diff --git a/lib/src/weibo_kit_platform_interface.dart b/lib/src/weibo_kit_platform_interface.dart index 5429b89..226276c 100644 --- a/lib/src/weibo_kit_platform_interface.dart +++ b/lib/src/weibo_kit_platform_interface.dart @@ -31,11 +31,9 @@ abstract class WeiboKitPlatform extends PlatformInterface { required String appKey, required String? universalLink, required List scope, - String redirectUrl = WeiboRegister - .DEFAULT_REDIRECTURL, // 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置 + String redirectUrl = WeiboRegister.DEFAULT_REDIRECTURL, // 新浪微博开放平台 -> 我的应用 -> 应用信息 -> 高级信息 -> OAuth2.0授权设置 }) { - throw UnimplementedError( - 'registerApp({required appKey, required universalLink, required scope, redirectUrl}) has not been implemented.'); + throw UnimplementedError('registerApp({required appKey, required universalLink, required scope, redirectUrl}) has not been implemented.'); } /// @@ -48,43 +46,66 @@ abstract class WeiboKitPlatform extends PlatformInterface { throw UnimplementedError('isInstalled() has not been implemented.'); } + /// + Future isSupportMultipleImage() { + throw UnimplementedError('isSupportMultipleImage() has not been implemented.'); + } + /// 登录 Future auth({ required String appKey, required List scope, String redirectUrl = WeiboRegister.DEFAULT_REDIRECTURL, }) { - throw UnimplementedError( - 'auth({required appKey, required scope, redirectUrl}) has not been implemented.'); + throw UnimplementedError('auth({required appKey, required scope, redirectUrl}) has not been implemented.'); } /// 分享 - 文本 Future shareText({ required String text, + bool clientOnly = false, }) { - throw UnimplementedError( - 'shareText({required text}) has not been implemented.'); + throw UnimplementedError('shareText({required text, clientOnly}) has not been implemented.'); } /// 分享 - 图片 + /// 图片文件分享用 shareMultiImage Future shareImage({ String? text, Uint8List? imageData, Uri? imageUri, + bool clientOnly = false, }) { - throw UnimplementedError( - 'shareImage({text, imageData, imageUri}) has not been implemented.'); + throw UnimplementedError('shareImage({text, imageData, imageUri, clientOnly}) has not been implemented.'); + } + + /// 分享 - 多图 + Future shareMultiImage({ + String? text, + required List imageUris, + bool clientOnly = false, + }) { + throw UnimplementedError('shareMultiImage({text, required imageUris, clientOnly}) has not been implemented.'); + } + + /// 分享 - 视频 + Future shareVideo({ + String? text, + required Uri videoUri, + bool clientOnly = false, + }) { + throw UnimplementedError('shareVideo({text, required videoUri, clientOnly}) has not been implemented.'); } /// 分享 - 网页 - @Deprecated('iOS:分享多媒体已经弃用 请不要用相关api') + /// iOS:分享多媒体已经弃用 请不要用相关api Future shareWebpage({ required String title, required String description, required Uint8List thumbData, required String webpageUrl, + bool clientOnly = false, }) { - throw UnimplementedError( - 'shareWebpage({required title, required description, required thumbData, required webpageUrl}) has not been implemented.'); + throw UnimplementedError('shareWebpage({required title, required description, required thumbData, required webpageUrl, clientOnly}) has not been implemented.'); } } diff --git a/test/weibo_kit_test.dart b/test/weibo_kit_test.dart index 56ef90a..fc7144e 100644 --- a/test/weibo_kit_test.dart +++ b/test/weibo_kit_test.dart @@ -31,6 +31,11 @@ class MockWeiboKitPlatform throw UnimplementedError(); } + @override + Future isSupportMultipleImage() { + throw UnimplementedError(); + } + @override Future auth({ required String appKey, @@ -43,6 +48,7 @@ class MockWeiboKitPlatform @override Future shareText({ required String text, + bool clientOnly = false, }) { throw UnimplementedError(); } @@ -52,6 +58,25 @@ class MockWeiboKitPlatform String? text, Uint8List? imageData, Uri? imageUri, + bool clientOnly = false, + }) { + throw UnimplementedError(); + } + + @override + Future shareMultiImage({ + String? text, + required List imageUris, + bool clientOnly = false, + }) { + throw UnimplementedError(); + } + + @override + Future shareVideo({ + String? text, + required Uri videoUri, + bool clientOnly = false, }) { throw UnimplementedError(); } @@ -62,6 +87,7 @@ class MockWeiboKitPlatform required String description, required Uint8List thumbData, required String webpageUrl, + bool clientOnly = false, }) { throw UnimplementedError(); }