提交 178d85fa authored 作者: JarvanMo's avatar JarvanMo

better support for sharing files

fix bug when sharing mini program on android
上级 42995b28
...@@ -7,7 +7,6 @@ import android.content.pm.PackageManager ...@@ -7,7 +7,6 @@ import android.content.pm.PackageManager
import android.content.res.AssetFileDescriptor import android.content.res.AssetFileDescriptor
import android.net.Uri import android.net.Uri
import android.text.TextUtils import android.text.TextUtils
import android.util.Log
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider import androidx.core.content.FileProvider
import com.jarvan.fluwx.io.* import com.jarvan.fluwx.io.*
...@@ -66,6 +65,7 @@ internal class FluwxShareHandlerCompat(private val registrar: PluginRegistry.Reg ...@@ -66,6 +65,7 @@ internal class FluwxShareHandlerCompat(private val registrar: PluginRegistry.Reg
internal interface FluwxShareHandler : CoroutineScope { internal interface FluwxShareHandler : CoroutineScope {
companion object { companion object {
const val SHARE_IMAGE_THUMB_LENGTH = 32 * 1024 const val SHARE_IMAGE_THUMB_LENGTH = 32 * 1024
const val SHARE_MINI_PROGRAM_THUMB_LENGTH = 120 * 1024
private const val keyTitle = "title" private const val keyTitle = "title"
private const val keyThumbnail = "thumbnail" private const val keyThumbnail = "thumbnail"
private const val keyDescription = "description" private const val keyDescription = "description"
...@@ -114,7 +114,7 @@ internal interface FluwxShareHandler : CoroutineScope { ...@@ -114,7 +114,7 @@ internal interface FluwxShareHandler : CoroutineScope {
msg.description = call.argument(keyDescription) // 小程序消息desc msg.description = call.argument(keyDescription) // 小程序消息desc
launch { launch {
msg.thumbData = readThumbnailByteArray(call) msg.thumbData = readThumbnailByteArray(call, length = SHARE_MINI_PROGRAM_THUMB_LENGTH)
val req = SendMessageToWX.Req() val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg) setCommonArguments(call, req, msg)
...@@ -126,7 +126,7 @@ internal interface FluwxShareHandler : CoroutineScope { ...@@ -126,7 +126,7 @@ internal interface FluwxShareHandler : CoroutineScope {
private fun shareImage(call: MethodCall, result: MethodChannel.Result) { private fun shareImage(call: MethodCall, result: MethodChannel.Result) {
launch { launch {
val map: Map<String, Any> = call.argument("source") ?: mapOf() val map: Map<String, Any> = call.argument("source") ?: mapOf()
val sourceImage = WeChatImage.createWeChatImage(map, assetFileDescriptor) val sourceImage = WeChatFile.createWeChatFile(map, assetFileDescriptor)
val thumbData = readThumbnailByteArray(call) val thumbData = readThumbnailByteArray(call)
val sourceByteArray = sourceImage.readByteArray() val sourceByteArray = sourceImage.readByteArray()
...@@ -134,7 +134,7 @@ internal interface FluwxShareHandler : CoroutineScope { ...@@ -134,7 +134,7 @@ internal interface FluwxShareHandler : CoroutineScope {
sourceByteArray.isEmpty() -> { sourceByteArray.isEmpty() -> {
WXImageObject() WXImageObject()
} }
sourceByteArray.size > 512 * 1024 -> { sourceByteArray.size > 500 * 1024 -> {
WXImageObject().apply { WXImageObject().apply {
if (supportFileProvider && targetHigherThanN) { if (supportFileProvider && targetHigherThanN) {
setImagePath(getFileContentUri(sourceByteArray.toCacheFile(context, sourceImage.suffix))) setImagePath(getFileContentUri(sourceByteArray.toCacheFile(context, sourceImage.suffix)))
...@@ -232,15 +232,27 @@ internal interface FluwxShareHandler : CoroutineScope { ...@@ -232,15 +232,27 @@ internal interface FluwxShareHandler : CoroutineScope {
} }
private fun shareFile(call: MethodCall, result: MethodChannel.Result) { private fun shareFile(call: MethodCall, result: MethodChannel.Result) {
val file = WXFileObject() launch {
val filePath: String? = call.argument("filePath")
file.filePath = filePath val wxFileObject = WXFileObject()
// val filePath: String? = call.argument("filePath")
// wxFileObject.filePath = filePath
val msg = WXMediaMessage() val msg = WXMediaMessage()
msg.mediaObject = file msg.mediaObject = wxFileObject
msg.description = call.argument("description") msg.description = call.argument("description")
launch { val map: Map<String, Any> = call.argument("source") ?: mapOf()
val sourceFile = WeChatFile.createWeChatFile(map, assetFileDescriptor)
val sourceByteArray = sourceFile.readByteArray()
if (ContextCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
wxFileObject.filePath = sourceByteArray.toExternalCacheFile(context, sourceFile.suffix)?.absolutePath
} else {
permissionHandler?.requestStoragePermission()
}
msg.thumbData = readThumbnailByteArray(call) msg.thumbData = readThumbnailByteArray(call)
val req = SendMessageToWX.Req() val req = SendMessageToWX.Req()
setCommonArguments(call, req, msg) setCommonArguments(call, req, msg)
...@@ -253,16 +265,16 @@ internal interface FluwxShareHandler : CoroutineScope { ...@@ -253,16 +265,16 @@ internal interface FluwxShareHandler : CoroutineScope {
result.success(WXAPiHandler.wxApi?.sendReq(request)) result.success(WXAPiHandler.wxApi?.sendReq(request))
} }
private suspend fun readThumbnailByteArray(call: MethodCall): ByteArray? { private suspend fun readThumbnailByteArray(call: MethodCall, length: Int = SHARE_IMAGE_THUMB_LENGTH): ByteArray? {
val thumbnailMap: Map<String, Any>? = call.argument(keyThumbnail) val thumbnailMap: Map<String, Any>? = call.argument(keyThumbnail)
return thumbnailMap?.run { return thumbnailMap?.run {
val thumbnailImage = WeChatImage.createWeChatImage(thumbnailMap, assetFileDescriptor) val thumbnailImage = WeChatFile.createWeChatFile(thumbnailMap, assetFileDescriptor)
val thumbnailImageIO = ImagesIOIml(thumbnailImage) val thumbnailImageIO = ImagesIOIml(thumbnailImage)
compressThumbnail(thumbnailImageIO) compressThumbnail(thumbnailImageIO, length)
} }
} }
private suspend fun compressThumbnail(ioIml: ImagesIO) = ioIml.compressedByteArray(context, SHARE_IMAGE_THUMB_LENGTH) private suspend fun compressThumbnail(ioIml: ImagesIO, length: Int) = ioIml.compressedByteArray(context, length)
// SESSION, TIMELINE, FAVORITE // SESSION, TIMELINE, FAVORITE
private fun setCommonArguments(call: MethodCall, req: SendMessageToWX.Req, msg: WXMediaMessage) { private fun setCommonArguments(call: MethodCall, req: SendMessageToWX.Req, msg: WXMediaMessage) {
......
...@@ -37,7 +37,6 @@ internal suspend fun ByteArray.toCacheFile(context: Context, suffix: String): Fi ...@@ -37,7 +37,6 @@ internal suspend fun ByteArray.toCacheFile(context: Context, suffix: String): Fi
} }
} }
file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix) file = File(dir.absolutePath + File.separator + UUID.randomUUID().toString() + suffix)
return saveToLocal(this, file) return saveToLocal(this, file)
} }
......
...@@ -4,7 +4,6 @@ import android.content.Context ...@@ -4,7 +4,6 @@ import android.content.Context
import android.graphics.Bitmap import android.graphics.Bitmap
import android.graphics.Bitmap.CompressFormat import android.graphics.Bitmap.CompressFormat
import android.graphics.BitmapFactory import android.graphics.BitmapFactory
import android.util.Log
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import okio.* import okio.*
...@@ -18,7 +17,7 @@ import kotlin.math.sqrt ...@@ -18,7 +17,7 @@ import kotlin.math.sqrt
* 冷风如刀,以大地为砧板,视众生为鱼肉。 * 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。 * 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/ **/
class ImagesIOIml(override val image: WeChatImage) : ImagesIO { class ImagesIOIml(override val image: WeChatFile) : ImagesIO {
override suspend fun readByteArray(): ByteArray = image.readByteArray() override suspend fun readByteArray(): ByteArray = image.readByteArray()
...@@ -115,7 +114,7 @@ class ImagesIOIml(override val image: WeChatImage) : ImagesIO { ...@@ -115,7 +114,7 @@ class ImagesIOIml(override val image: WeChatImage) : ImagesIO {
} }
interface ImagesIO { interface ImagesIO {
val image: WeChatImage val image: WeChatFile
suspend fun readByteArray(): ByteArray suspend fun readByteArray(): ByteArray
suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray suspend fun compressedByteArray(context: Context, maxSize: Int): ByteArray
} }
...@@ -13,14 +13,14 @@ import java.io.File ...@@ -13,14 +13,14 @@ import java.io.File
import java.io.FileNotFoundException import java.io.FileNotFoundException
import java.io.IOException import java.io.IOException
/*** /***
* Created by mo on 2020/3/7 * Created by mo on 2020/5/13
* 冷风如刀,以大地为砧板,视众生为鱼肉。 * 冷风如刀,以大地为砧板,视众生为鱼肉。
* 万里飞雪,将穹苍作烘炉,熔万物为白银。 * 万里飞雪,将穹苍作烘炉,熔万物为白银。
**/ **/
class WeChatFileImage(override val source: Any, override val suffix: String) : WeChatImage {
class WeChatFileFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: File private var internalSource: File
init { init {
...@@ -46,7 +46,7 @@ class WeChatFileImage(override val source: Any, override val suffix: String) : W ...@@ -46,7 +46,7 @@ class WeChatFileImage(override val source: Any, override val suffix: String) : W
} }
} }
private class WeChatAssetImage(override val source: Any, override val suffix: String) : WeChatImage { private class WeChatAssetFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: AssetFileDescriptor private var internalSource: AssetFileDescriptor
init { init {
...@@ -72,7 +72,7 @@ private class WeChatAssetImage(override val source: Any, override val suffix: St ...@@ -72,7 +72,7 @@ private class WeChatAssetImage(override val source: Any, override val suffix: St
} }
} }
private class WeChatNetworkImage(override val source: Any, override val suffix: String) : WeChatImage { private class WeChatNetworkFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: String private var internalSource: String
init { init {
...@@ -100,7 +100,7 @@ private class WeChatNetworkImage(override val source: Any, override val suffix: ...@@ -100,7 +100,7 @@ private class WeChatNetworkImage(override val source: Any, override val suffix:
} }
} }
private class WeChatMemoryImage(override val source: Any, override val suffix: String) : WeChatImage { private class WeChatMemoryFile(override val source: Any, override val suffix: String) : WeChatFile {
private var internalSource: ByteArray private var internalSource: ByteArray
init { init {
...@@ -113,7 +113,7 @@ private class WeChatMemoryImage(override val source: Any, override val suffix: S ...@@ -113,7 +113,7 @@ private class WeChatMemoryImage(override val source: Any, override val suffix: S
override suspend fun readByteArray(): ByteArray = internalSource override suspend fun readByteArray(): ByteArray = internalSource
} }
interface WeChatImage { interface WeChatFile {
val source: Any val source: Any
val suffix: String val suffix: String
...@@ -124,16 +124,16 @@ interface WeChatImage { ...@@ -124,16 +124,16 @@ interface WeChatImage {
// ASSET, // ASSET,
// FILE, // FILE,
// BINARY, // BINARY,
fun createWeChatImage(params: Map<String, Any>, assetFileDescriptor: (String) -> AssetFileDescriptor): WeChatImage { fun createWeChatFile(params: Map<String, Any>, assetFileDescriptor: (String) -> AssetFileDescriptor): WeChatFile {
// Map toMap() => {"source": source, "schema": schema.index, "suffix": suffix}; // Map toMap() => {"source": source, "schema": schema.index, "suffix": suffix};
val suffix = (params["suffix"] as String?) ?: ".jpeg" val suffix = (params["suffix"] as String?) ?: ".jpeg"
return when ((params["schema"] as? Int) ?: 0) { return when ((params["schema"] as? Int) ?: 0) {
0 -> WeChatNetworkImage(source = (params["source"] as? String).orEmpty(), suffix = suffix) 0 -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix)
1 -> WeChatAssetImage(source = assetFileDescriptor(((params["source"] as? String).orEmpty())), suffix = suffix) 1 -> WeChatAssetFile(source = assetFileDescriptor(((params["source"] as? String).orEmpty())), suffix = suffix)
2 -> WeChatFileImage(source = File((params["source"] as? String).orEmpty()), suffix = suffix) 2 -> WeChatFileFile(source = File((params["source"] as? String).orEmpty()), suffix = suffix)
3 -> WeChatMemoryImage(source = (params["source"] as? ByteArray) 3 -> WeChatMemoryFile(source = (params["source"] as? ByteArray)
?: byteArrayOf(), suffix = suffix) ?: byteArrayOf(), suffix = suffix)
else -> WeChatNetworkImage(source = (params["source"] as? String).orEmpty(), suffix = suffix) else -> WeChatNetworkFile(source = (params["source"] as? String).orEmpty(), suffix = suffix)
} }
} }
} }
......
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"fluwx","path":"/Users/mo/Code/Other/fluwx/","dependencies":[]}],"android":[{"name":"fluwx","path":"/Users/mo/Code/Other/fluwx/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"fluwx","dependencies":[]}],"date_created":"2020-05-12 17:06:39.777970","version":"1.17.0"} {"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"fluwx","path":"/Users/mo/Code/Other/fluwx/","dependencies":[]}],"android":[{"name":"fluwx","path":"/Users/mo/Code/Other/fluwx/","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"fluwx","dependencies":[]}],"date_created":"2020-05-14 12:16:23.046621","version":"1.17.0"}
\ No newline at end of file \ No newline at end of file
...@@ -28,6 +28,7 @@ NSString *const fluwxKeySession = @"session"; ...@@ -28,6 +28,7 @@ NSString *const fluwxKeySession = @"session";
NSString *const fluwxKeyFavorite = @"favorite"; NSString *const fluwxKeyFavorite = @"favorite";
NSString *const keySource = @"source"; NSString *const keySource = @"source";
NSString *const keySuffix = @"suffix";
CGFloat thumbnailWidth; CGFloat thumbnailWidth;
...@@ -75,9 +76,17 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -75,9 +76,17 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
dispatch_async(globalQueue, ^{ dispatch_async(globalQueue, ^{
NSDictionary *sourceImage = call.arguments[keySource]; NSDictionary *sourceImage = call.arguments[keySource];
NSData *sourceImageData = [self getNsDataFromWeChatImage:sourceImage]; NSData *sourceImageData = [self getNsDataFromWeChatFile:sourceImage];
UIImage *thumbnailImage = [self getCommonThumbnail:call]; UIImage *thumbnailImage = [self getCommonThumbnail:call];
UIImage *realThumbnailImage;
if (thumbnailImage == nil) {
NSString *suffix = sourceImage[@"suffix"];
BOOL isPNG = [self isPNG:suffix];
realThumbnailImage = [self getThumbnailFromNSData:sourceImageData size:defaultThumbnailSize isPNG:isPNG];
} else {
realThumbnailImage = thumbnailImage;
}
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
...@@ -86,7 +95,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -86,7 +95,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
TagName:call.arguments[fluwxKeyMediaTagName] TagName:call.arguments[fluwxKeyMediaTagName]
MessageExt:call.arguments[fluwxKeyMessageExt] MessageExt:call.arguments[fluwxKeyMessageExt]
Action:call.arguments[fluwxKeyMessageAction] Action:call.arguments[fluwxKeyMessageAction]
ThumbImage:thumbnailImage ThumbImage:realThumbnailImage
InScene:[self intToWeChatScene:scene] InScene:[self intToWeChatScene:scene]
title:call.arguments[fluwxKeyTitle] title:call.arguments[fluwxKeyTitle]
description:call.arguments[fluwxKeyDescription] description:call.arguments[fluwxKeyDescription]
...@@ -184,15 +193,22 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -184,15 +193,22 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
- (void)shareFile:(FlutterMethodCall *)call result:(FlutterResult)result { - (void)shareFile:(FlutterMethodCall *)call result:(FlutterResult)result {
dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0); dispatch_queue_t globalQueue = dispatch_get_global_queue(0, 0);
dispatch_async(globalQueue, ^{ dispatch_async(globalQueue, ^{
NSDictionary *sourceFile = call.arguments[keySource];
UIImage *thumbnailImage = [self getCommonThumbnail:call]; UIImage *thumbnailImage = [self getCommonThumbnail:call];
NSString *fileExtension;
NSString *suffix = sourceFile[keySuffix];
fileExtension = suffix;
if ([suffix hasPrefix:@"."]) {
NSRange range = NSMakeRange(0, 1);
fileExtension = [suffix stringByReplacingCharactersInRange:range withString:@""];
}
NSString *filePath = call.arguments[@"filePath"]; NSData *data = [self getNsDataFromWeChatFile:sourceFile];
NSData *data = [NSData dataWithContentsOfFile:filePath];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
NSNumber *scene = call.arguments[fluwxKeyScene]; NSNumber *scene = call.arguments[fluwxKeyScene];
[WXApiRequestHandler sendFileData:data [WXApiRequestHandler sendFileData:data
fileExtension:call.arguments[@"fileExtension"] fileExtension:fileExtension
Title:call.arguments[fluwxKeyTitle] Title:call.arguments[fluwxKeyTitle]
Description:call.arguments[fluwxKeyDescription] Description:call.arguments[fluwxKeyDescription]
ThumbImage:thumbnailImage ThumbImage:thumbnailImage
...@@ -213,8 +229,8 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -213,8 +229,8 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
NSData *hdImageData = nil; NSData *hdImageData = nil;
NSDictionary *hdImagePath = call.arguments[@"hdImagePath"]; NSDictionary *hdImagePath = call.arguments[@"hdImagePath"];
if (hdImageData != nil && hdImagePath != (id) [NSNull null]) { if (hdImagePath != (id) [NSNull null]) {
NSData *imageData = [self getNsDataFromWeChatImage:hdImagePath]; NSData *imageData = [self getNsDataFromWeChatFile:hdImagePath];
NSString *suffix = hdImagePath[@"suffix"]; NSString *suffix = hdImagePath[@"suffix"];
BOOL isPNG = [self isPNG:suffix]; BOOL isPNG = [self isPNG:suffix];
UIImage *uiImage = [self getThumbnailFromNSData:imageData size:120 * 1024 isPNG:isPNG]; UIImage *uiImage = [self getThumbnailFromNSData:imageData size:120 * 1024 isPNG:isPNG];
...@@ -268,7 +284,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -268,7 +284,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
} }
NSString *suffix = thumbnail[@"suffix"]; NSString *suffix = thumbnail[@"suffix"];
NSData *thumbnailData = [self getNsDataFromWeChatImage:thumbnail]; NSData *thumbnailData = [self getNsDataFromWeChatFile:thumbnail];
UIImage *thumbnailImage = [self getThumbnailFromNSData:thumbnailData size:defaultThumbnailSize isPNG:[self isPNG:suffix]]; UIImage *thumbnailImage = [self getThumbnailFromNSData:thumbnailData size:defaultThumbnailSize isPNG:[self isPNG:suffix]];
return thumbnailImage; return thumbnailImage;
} }
...@@ -279,22 +295,22 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -279,22 +295,22 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
// FILE, // FILE,
// BINARY, // BINARY,
//} //}
- (NSData *)getNsDataFromWeChatImage:(NSDictionary *)weChatImage { - (NSData *)getNsDataFromWeChatFile:(NSDictionary *)weChatFile {
NSNumber *schema = weChatImage[@"schema"]; NSNumber *schema = weChatFile[@"schema"];
if ([schema isEqualToNumber:@0]) { if ([schema isEqualToNumber:@0]) {
NSString *source = weChatImage[keySource]; NSString *source = weChatFile[keySource];
NSURL *imageURL = [NSURL URLWithString:source]; NSURL *imageURL = [NSURL URLWithString:source];
//下载图片 //下载图片
return [NSData dataWithContentsOfURL:imageURL]; return [NSData dataWithContentsOfURL:imageURL];
} else if ([schema isEqualToNumber:@1]) { } else if ([schema isEqualToNumber:@1]) {
NSString *source = weChatImage[keySource]; NSString *source = weChatFile[keySource];
return [NSData dataWithContentsOfFile:[self readImageFromAssets:source]]; return [NSData dataWithContentsOfFile:[self readFileFromAssets:source]];
} else if ([schema isEqualToNumber:@2]) { } else if ([schema isEqualToNumber:@2]) {
NSString *source = weChatImage[keySource]; NSString *source = weChatFile[keySource];
return [NSData dataWithContentsOfFile:source]; return [NSData dataWithContentsOfFile:source];
} else if ([schema isEqualToNumber:@3]) { } else if ([schema isEqualToNumber:@3]) {
FlutterStandardTypedData *imageData = weChatImage[@"source"]; FlutterStandardTypedData *imageData = weChatFile[@"source"];
return imageData.data; return imageData.data;
} else { } else {
return nil; return nil;
...@@ -306,7 +322,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar; ...@@ -306,7 +322,7 @@ NSObject <FlutterPluginRegistrar> *_fluwxRegistrar;
return [ThumbnailHelper compressImage:uiImage toByte:size isPNG:isPNG]; return [ThumbnailHelper compressImage:uiImage toByte:size isPNG:isPNG];
} }
- (NSString *)readImageFromAssets:(NSString *)imagePath { - (NSString *)readFileFromAssets:(NSString *)imagePath {
NSArray *array = [self formatAssets:imagePath]; NSArray *array = [self formatAssets:imagePath];
NSString *key; NSString *key;
if ([FluwxStringUtil isBlank:array[1]]) { if ([FluwxStringUtil isBlank:array[1]]) {
......
...@@ -8,4 +8,4 @@ export 'package:fluwx/src/fluwx_iml.dart'; ...@@ -8,4 +8,4 @@ export 'package:fluwx/src/fluwx_iml.dart';
export 'package:fluwx/src/response/wechat_response.dart'; export 'package:fluwx/src/response/wechat_response.dart';
export 'package:fluwx/src/share/share_models.dart'; export 'package:fluwx/src/share/share_models.dart';
export 'package:fluwx/src/wechat_enums.dart'; export 'package:fluwx/src/wechat_enums.dart';
export 'package:fluwx/src/wechat_image.dart' hide ImageSchema; export 'package:fluwx/src/wechat_file.dart' hide FileSchema;
...@@ -288,10 +288,11 @@ class WeChatShareWebPageModel implements WeChatShareBaseModel { ...@@ -288,10 +288,11 @@ class WeChatShareWebPageModel implements WeChatShareBaseModel {
} }
} }
/// [source] the file you want to share, [source.suffix] is necessary on iOS.
/// [scene] can't be [WeChatScene.TIMELINE], otherwise, sharing nothing.
/// send files to WeChat /// send files to WeChat
class WeChatShareFileModel implements WeChatShareBaseModel { class WeChatShareFileModel implements WeChatShareBaseModel {
final String filePath; final WeChatFile source;
final String fileExtension;
final WeChatImage thumbnail; final WeChatImage thumbnail;
final String title; final String title;
final String description; final String description;
...@@ -300,24 +301,22 @@ class WeChatShareFileModel implements WeChatShareBaseModel { ...@@ -300,24 +301,22 @@ class WeChatShareFileModel implements WeChatShareBaseModel {
final String messageAction; final String messageAction;
final String mediaTagName; final String mediaTagName;
WeChatShareFileModel(this.filePath, WeChatShareFileModel(this.source,
{this.fileExtension: "pdf", {this.title: "",
this.title: "",
this.description: "", this.description: "",
this.thumbnail, this.thumbnail,
this.scene = WeChatScene.SESSION, this.scene = WeChatScene.SESSION,
this.mediaTagName, this.mediaTagName,
this.messageAction, this.messageAction,
this.messageExt}) this.messageExt})
: assert(filePath != null), : assert(source != null),
assert(scene != null); assert(scene != null);
@override @override
Map toMap() { Map toMap() {
return { return {
_scene: scene.index, _scene: scene.index,
"filePath": filePath, _source: source.toMap(),
"fileExtension": fileExtension,
_thumbnail: thumbnail?.toMap(), _thumbnail: thumbnail?.toMap(),
_title: title, _title: title,
_description: description, _description: description,
......
...@@ -19,37 +19,54 @@ ...@@ -19,37 +19,54 @@
import 'dart:io'; import 'dart:io';
import 'dart:typed_data'; import 'dart:typed_data';
class WeChatImage { const String defaultSuffixJpeg = ".jpeg";
const String defaultSuffixTxt = ".txt";
class WeChatImage extends WeChatFile {
WeChatImage.network(String source, {String suffix = defaultSuffixJpeg})
: super.network(source, suffix: suffix);
WeChatImage.asset(String source, {String suffix = defaultSuffixJpeg})
: super.asset(source, suffix: suffix);
WeChatImage.file(File source, {String suffix = defaultSuffixJpeg})
: super.file(source, suffix: suffix);
WeChatImage.binary(Uint8List source, {String suffix = defaultSuffixJpeg})
: super.binary(source, suffix: suffix);
}
class WeChatFile {
final dynamic source; final dynamic source;
final ImageSchema schema; final FileSchema schema;
final String suffix; final String suffix;
/// [source] must begin with http or https /// [source] must begin with http or https
WeChatImage.network(String source, {String suffix}) WeChatFile.network(String source, {String suffix})
: assert(source != null && source.startsWith("http")), : assert(source != null && source.startsWith("http")),
this.source = source, this.source = source,
this.schema = ImageSchema.NETWORK, this.schema = FileSchema.NETWORK,
this.suffix = source.readSuffix(suffix); this.suffix = source.readSuffix(suffix, defaultSuffixTxt);
///[source] path of the image, like '/asset/image.jpeg?package=flutter', ///[source] path of the image, like '/asset/image.pdf?package=flutter',
///the query param package in [source] only available when you want to specify the package of image ///the query param package in [source] only available when you want to specify the package of image
WeChatImage.asset(String source, {String suffix}) WeChatFile.asset(String source, {String suffix})
: assert(source != null && source.trim().isNotEmpty), : assert(source != null && source.trim().isNotEmpty),
this.source = source, this.source = source,
this.schema = ImageSchema.ASSET, this.schema = FileSchema.ASSET,
this.suffix = source.readSuffix(suffix); this.suffix = source.readSuffix(suffix, defaultSuffixTxt);
WeChatImage.file(File source, {String suffix = ".jpeg"}) WeChatFile.file(File source, {String suffix = defaultSuffixTxt})
: assert(source != null), : assert(source != null),
this.source = source.path, this.source = source.path,
this.schema = ImageSchema.FILE, this.schema = FileSchema.FILE,
this.suffix = source.path.readSuffix(suffix); this.suffix = source.path.readSuffix(suffix, defaultSuffixTxt);
WeChatImage.binary(Uint8List source, {String suffix = ".jpeg"}) WeChatFile.binary(Uint8List source, {String suffix = defaultSuffixTxt})
: assert(source != null), : assert(source != null),
assert(suffix != null && suffix.trim().isNotEmpty), assert(suffix != null && suffix.trim().isNotEmpty),
this.source = source, this.source = source,
this.schema = ImageSchema.BINARY, this.schema = FileSchema.BINARY,
this.suffix = suffix; this.suffix = suffix;
Map toMap() => Map toMap() =>
...@@ -57,22 +74,22 @@ class WeChatImage { ...@@ -57,22 +74,22 @@ class WeChatImage {
} }
///Types of image, usually there are for types listed below. ///Types of image, usually there are for types listed below.
///[ImageSchema.NETWORK] is online images. ///[FileSchema.NETWORK] is online images.
///[ImageSchema.ASSET] is flutter asset image. ///[FileSchema.ASSET] is flutter asset image.
///[ImageSchema.BINARY] is binary image, shall be be [Uint8List] ///[FileSchema.BINARY] is binary image, shall be be [Uint8List]
///[ImageSchema.FILE] is local file, usually not comes from flutter asset. ///[FileSchema.FILE] is local file, usually not comes from flutter asset.
enum ImageSchema { enum FileSchema {
NETWORK, NETWORK,
ASSET, ASSET,
FILE, FILE,
BINARY, BINARY,
} }
extension _ImageSuffix on String { extension _FileSuffix on String {
/// returns [suffix] if [suffix] not blank. /// returns [suffix] if [suffix] not blank.
/// If [suffix] is blank, then try to read from url /// If [suffix] is blank, then try to read from url
/// if suffix in url not found, then return jpg as default. /// if suffix in url not found, then return jpg as default.
String readSuffix(String suffix) { String readSuffix(String suffix, String defaultSuffix) {
if (suffix != null && suffix.trim().isNotEmpty) { if (suffix != null && suffix.trim().isNotEmpty) {
if (suffix.startsWith(".")) { if (suffix.startsWith(".")) {
return suffix; return suffix;
...@@ -87,6 +104,6 @@ extension _ImageSuffix on String { ...@@ -87,6 +104,6 @@ extension _ImageSuffix on String {
if (index >= 0) { if (index >= 0) {
return path.substring(index); return path.substring(index);
} }
return ".jpeg"; return defaultSuffix;
} }
} }
...@@ -18,7 +18,7 @@ ...@@ -18,7 +18,7 @@
*/ */
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:fluwx/fluwx.dart'; import 'package:fluwx/fluwx.dart';
import 'package:fluwx/src/wechat_image.dart'; import 'package:fluwx/src/wechat_file.dart';
void main() { void main() {
...@@ -27,20 +27,20 @@ void main() { ...@@ -27,20 +27,20 @@ void main() {
WeChatImage.network("http://image.openflutter.dev/fluwx.png"); WeChatImage.network("http://image.openflutter.dev/fluwx.png");
expect(withSuffixImage.source, "http://image.openflutter.dev/fluwx.png"); expect(withSuffixImage.source, "http://image.openflutter.dev/fluwx.png");
expect(withSuffixImage.suffix, ".png"); expect(withSuffixImage.suffix, ".png");
expect(ImageSchema.NETWORK, withSuffixImage.schema); expect(FileSchema.NETWORK, withSuffixImage.schema);
var withNoSuffixNoUrlSuffixImage = var withNoSuffixNoUrlSuffixImage =
WeChatImage.network("http://image.openflutter.dev/fluwx"); WeChatImage.network("http://image.openflutter.dev/fluwx");
expect("http://image.openflutter.dev/fluwx", expect("http://image.openflutter.dev/fluwx",
withNoSuffixNoUrlSuffixImage.source); withNoSuffixNoUrlSuffixImage.source);
expect(withNoSuffixNoUrlSuffixImage.suffix, ".jpeg"); expect(withNoSuffixNoUrlSuffixImage.suffix, ".jpeg");
expect(ImageSchema.NETWORK, withSuffixImage.schema); expect(FileSchema.NETWORK, withSuffixImage.schema);
var withSpecifiedSuffixImage = WeChatImage.network( var withSpecifiedSuffixImage = WeChatImage.network(
"http://image.openflutter.dev/fluwx.jpeg", "http://image.openflutter.dev/fluwx.jpeg",
suffix: ".png"); suffix: ".png");
expect(withSpecifiedSuffixImage.source, "http://image.openflutter.dev/fluwx.jpeg"); expect(withSpecifiedSuffixImage.source, "http://image.openflutter.dev/fluwx.jpeg");
expect(withSpecifiedSuffixImage.suffix, ".png"); expect(withSpecifiedSuffixImage.suffix, ".png");
expect(withSpecifiedSuffixImage.schema, ImageSchema.NETWORK); expect(withSpecifiedSuffixImage.schema, FileSchema.NETWORK);
}); });
} }
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论