From 6ff72d21e4b329b838571f02a026a95ed027f7e1 Mon Sep 17 00:00:00 2001 From: Yifei Xu Date: Fri, 27 Jun 2025 18:30:50 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E5=88=86=E4=BA=AB=20gif=20?= =?UTF-8?q?=E5=8A=A8=E5=9B=BE=E5=88=B0=E8=81=8A=E5=A4=A9=E7=9A=84=E5=B0=81?= =?UTF-8?q?=E8=A3=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fluwx/handlers/FluwxShareHandler.kt | 47 +++++++++++++++++++ ios/Classes/FluwxPlugin.m | 33 +++++++++++++ lib/src/foundation/share_models.dart | 26 ++++++++++ .../method_channel/fluwx_method_channel.dart | 8 +++- 4 files changed, 112 insertions(+), 2 deletions(-) diff --git a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt b/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt index edda5e47..0df3632c 100644 --- a/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt +++ b/android/src/main/kotlin/com/jarvan/fluwx/handlers/FluwxShareHandler.kt @@ -16,6 +16,8 @@ import java.io.File import java.io.IOException import java.util.* import kotlin.coroutines.CoroutineContext +import android.os.Build +import io.flutter.plugin.common.MethodChannel.Result /*** @@ -65,6 +67,7 @@ internal interface FluwxShareHandler : CoroutineScope { "shareVideo" -> shareVideo(call, result) "shareWebPage" -> shareWebPage(call, result) "shareFile" -> shareFile(call, result) + "shareEmoji" -> shareEmoji(call, result) else -> { result.notImplemented() } @@ -266,6 +269,39 @@ internal interface FluwxShareHandler : CoroutineScope { } } + private fun shareEmoji(call: MethodCall, result: Result) { + + val scene = call.argument("scene") ?: 0 + val title = call.argument("title") + val desc = call.argument("description") + val thumbData = call.argument("thumbData") + + val emojiMap = call.argument>("source") + ?: run { result.error("ARG", "emoji is null", null); return } + + val emojiObj = WXEmojiObject().apply { + when { + emojiMap["uint8List"] != null -> emojiData = emojiMap["uint8List"] as ByteArray + emojiMap["path"] != null -> emojiPath = ensurePublicPath(emojiMap["path"] as String) + else -> { result.error("ARG", "gif source missing", null); return } + } + } + + val msg = WXMediaMessage(emojiObj).apply { + this.thumbData = thumbData + this.title = title + this.description = desc + } + + val req = SendMessageToWX.Req().apply { + transaction = "emoji${System.currentTimeMillis()}" + message = msg + this.scene = scene + } + + result.success(WXAPiHandler.wxApi?.sendReq(req)) + } + private suspend fun sendRequestInMain(result: MethodChannel.Result, request: BaseReq) = withContext(Dispatchers.Main) { result.success(WXAPiHandler.wxApi?.sendReq(request)) @@ -326,6 +362,17 @@ internal interface FluwxShareHandler : CoroutineScope { } + private fun loadBytesFromFlutterAsset(assetKey: String): ByteArray = + context.assets.open(assetKey.removePrefix("flutterassets/")).use { it.readBytes() } + + private fun ensurePublicPath(original: String): String { + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) return original + val src = File(original) + val dst = File(context.externalCacheDir, src.name) + if (!dst.exists()) src.copyTo(dst, overwrite = true) + return dst.path + } + private val supportFileProvider: Boolean get() = (WXAPiHandler.wxApi?.wxAppSupportAPI ?: 0) >= 0x27000D00 private val targetHigherThanN: Boolean get() = android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N diff --git a/ios/Classes/FluwxPlugin.m b/ios/Classes/FluwxPlugin.m index 5bc3801e..2f17e0ba 100644 --- a/ios/Classes/FluwxPlugin.m +++ b/ios/Classes/FluwxPlugin.m @@ -509,6 +509,8 @@ - (void)handleShare:(FlutterMethodCall *)call result:(FlutterResult)result { [self shareMiniProgram:call result:result]; } else if ([@"shareFile" isEqualToString:call.method]) { [self shareFile:call result:result]; + } else if ([@"shareEmoji" isEqualToString:call.method]) { + [self shareEmoji:call result:result]; } } @@ -739,6 +741,37 @@ - (void)shareMiniProgram:(FlutterMethodCall *)call result:(FlutterResult)result }); } +- (void)shareEmoji:(FlutterMethodCall *)call result:(FlutterResult)result { + + NSNumber *sceneNum = call.arguments[fluwxKeyScene]; + enum WXScene scene = [self intToWeChatScene:sceneNum]; + + NSDictionary *sourceEmoji = call.arguments[keySource]; + FlutterStandardTypedData *flutterEmojiData = sourceEmoji[@"uint8List"]; + NSData *emojiData = flutterEmojiData != nil ? flutterEmojiData.data : nil; + + FlutterStandardTypedData *flutterThumbData = call.arguments[fluwxKeyThumbData]; + NSData *thumbData = ![flutterThumbData isKindOfClass:[NSNull class]] ? flutterThumbData.data : nil; + + NSString *msgSignature = call.arguments[fluwxKeyMsgSignature]; + NSString *thumbHash = call.arguments[fluwxKeyThumbDataHash]; + + dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); + dispatch_async(globalQueue, ^{ + dispatch_async(dispatch_get_main_queue(), ^{ + + [self sendEmotionData:emojiData + InScene:scene + MsgSignature:msgSignature + ThumbData:thumbData + ThumbDataHash:thumbHash + completion:^(BOOL success) { + result(@(success)); + }]; + }); + }); +} + - (NSData *)getNsDataFromWeChatFile:(NSDictionary *)weChatFile { NSNumber *schema = weChatFile[@"schema"]; diff --git a/lib/src/foundation/share_models.dart b/lib/src/foundation/share_models.dart index 42c37d42..86216211 100644 --- a/lib/src/foundation/share_models.dart +++ b/lib/src/foundation/share_models.dart @@ -339,6 +339,32 @@ class WeChatShareFileModel extends WeChatShareModel { }; } +class WeChatShareEmojiModel extends WeChatShareModel { + final WeChatImageToShare emoji; + final WeChatScene scene; + + WeChatShareEmojiModel( + this.emoji, { + this.scene = WeChatScene.session, + super.title, + super.description, + super.msgSignature, + super.thumbData, + super.thumbDataHash, + }); + + @override + Map get arguments => { + _scene: scene.index, + _source: emoji.arguments, + _title: title, + _description: description, + _msgSignature: msgSignature, + _thumbData: thumbData, + _thumbDataHash: thumbDataHash, + }; +} + class WeChatImageToShare with _Argument { final Uint8List? uint8List; final String? localImagePath; diff --git a/lib/src/method_channel/fluwx_method_channel.dart b/lib/src/method_channel/fluwx_method_channel.dart index 48886855..41bb39ab 100644 --- a/lib/src/method_channel/fluwx_method_channel.dart +++ b/lib/src/method_channel/fluwx_method_channel.dart @@ -45,6 +45,7 @@ class MethodChannelFluwx extends FluwxPlatform { WeChatShareWebPageModel: 'shareWebPage', WeChatShareMiniProgramModel: 'shareMiniProgram', WeChatShareFileModel: 'shareFile', + WeChatShareEmojiModel: 'shareEmoji', }; final StreamController _responseEventHandler = @@ -100,9 +101,12 @@ class MethodChannelFluwx extends FluwxPlatform { Future open(OpenType target) async { switch (target) { case WeChatApp(): - return await methodChannel.invokeMethod('openWXApp', target.arguments) ?? false; + return await methodChannel.invokeMethod( + 'openWXApp', target.arguments) ?? + false; case Browser(): - return await methodChannel.invokeMethod('openUrl', target.arguments) ?? false; + return await methodChannel.invokeMethod('openUrl', target.arguments) ?? + false; case RankList(): return await methodChannel.invokeMethod("openRankList") ?? false; case BusinessView():