Commit 7d6ac863 authored by zhouteng's avatar zhouteng

修复android平台视频分享到微信失败的问题

parent 401f3580
......@@ -7,7 +7,7 @@
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.zt.shareextend.fileprovider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
......
package com.zt.shareextend;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.core.content.FileProvider;
import java.io.File;
import java.util.Map;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.PluginRegistry;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/**
* Plugin method host for presenting a share sheet via Intent
*/
public class ShareExtendPlugin implements MethodChannel.MethodCallHandler, PluginRegistry.RequestPermissionsResultListener {
/// the authorities for FileProvider
private static final String authorities = "com.zt.shareextend.fileprovider";
private static final int CODE_ASK_PERMISSION = 100;
private static final String CHANNEL = "share_extend";
......@@ -84,12 +78,14 @@ public class ShareExtendPlugin implements MethodChannel.MethodCallHandler, Plugi
}
File f = new File(text);
Uri uri = getUriForFile(mRegistrar.context(), f);
if ("file".equals(type)) {
shareIntent.setType("application/*");
}
Uri uri = ShareUtils.getUriForFile(mRegistrar.context(), f);
if ("image".equals(type)) {
shareIntent.setType("image/*");
} else if ("video".equals(type)) {
shareIntent.setType("video/*");
} else {
shareIntent.setType("application/*");
}
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
}
......@@ -127,12 +123,4 @@ public class ShareExtendPlugin implements MethodChannel.MethodCallHandler, Plugi
}
return false;
}
private static Uri getUriForFile(Context context, File file) {
if (Build.VERSION.SDK_INT >= 24) {
return FileProvider.getUriForFile(context, authorities, file);
} else {
return Uri.fromFile(file);
}
}
}
package com.zt.shareextend;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.text.TextUtils;
import java.io.File;
import androidx.core.content.FileProvider;
public class ShareUtils {
/// get the uri for file
public static Uri getUriForFile(Context context, File file) {
String authorities = context.getPackageName() + ".fileprovider";
Uri uri;
// 低版本直接用 Uri.fromFile
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
uri = Uri.fromFile(file);
} else {
// 使用 FileProvider 会在某些 app 下不支持(在使用FileProvider 方式情况下QQ不能支持图片、视频分享,微信不支持视频分享)
uri = FileProvider.getUriForFile(context, authorities, file);
ContentResolver cR = context.getContentResolver();
if (uri != null && !TextUtils.isEmpty(uri.toString())) {
String fileType = cR.getType(uri);
// 使用 MediaStore 的 content:// 而不是自己 FileProvider 提供的uri,不然有些app无法适配
if (!TextUtils.isEmpty(fileType)) {
if (fileType.contains("video/")) {
uri = getVideoContentUri(context, file);
} else if (fileType.contains("image/")) {
uri = getImageContentUri(context, file);
} else if (fileType.contains("audio/")) {
uri = getAudioContentUri(context, file);
}
}
}
}
return uri;
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param imageFile
* @return content Uri
*/
public static Uri getImageContentUri(Context context, File imageFile) {
String filePath = imageFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Images.Media._ID}, MediaStore.Images.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/images/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (imageFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Images.Media.DATA, filePath);
return context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param videoFile
* @return content Uri
*/
public static Uri getVideoContentUri(Context context, File videoFile) {
String filePath = videoFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Video.Media._ID}, MediaStore.Video.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/video/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (videoFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Video.Media.DATA, filePath);
return context.getContentResolver().insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
/**
* Gets the content:// URI from the given corresponding path to a file
*
* @param context
* @param audioFile
* @return content Uri
*/
public static Uri getAudioContentUri(Context context, File audioFile) {
String filePath = audioFile.getAbsolutePath();
Cursor cursor = context.getContentResolver().query(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI,
new String[]{MediaStore.Audio.Media._ID}, MediaStore.Audio.Media.DATA + "=? ",
new String[]{filePath}, null);
if (cursor != null && cursor.moveToFirst()) {
int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
Uri baseUri = Uri.parse("content://media/external/audio/media");
return Uri.withAppendedPath(baseUri, "" + id);
} else {
if (audioFile.exists()) {
ContentValues values = new ContentValues();
values.put(MediaStore.Audio.Media.DATA, filePath);
return context.getContentResolver().insert(MediaStore.Audio.Media.EXTERNAL_CONTENT_URI, values);
} else {
return null;
}
}
}
}
......@@ -15,7 +15,6 @@
3B80C3951E831B6300D905FE /* App.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 3B80C3931E831B6300D905FE /* App.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9705A1C61CF904A100538489 /* Flutter.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; };
9705A1C71CF904A300538489 /* Flutter.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 9740EEBA1CF902C7004384FC /* Flutter.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
9740EEB41CF90195004384FC /* Debug.xcconfig in Resources */ = {isa = PBXBuildFile; fileRef = 9740EEB21CF90195004384FC /* Debug.xcconfig */; };
978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; };
97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; };
97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; };
......@@ -176,7 +175,7 @@
97C146E61CF9000F007C117D /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0910;
LastUpgradeCheck = 1010;
ORGANIZATIONNAME = "The Chromium Authors";
TargetAttributes = {
97C146ED1CF9000F007C117D = {
......@@ -209,7 +208,6 @@
files = (
97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */,
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 */,
......@@ -332,12 +330,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
......@@ -386,12 +386,14 @@
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
......
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0910"
LastUpgradeVersion = "1010"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
......@@ -26,7 +26,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
shouldUseLaunchSchemeArgsEnv = "YES">
<Testables>
</Testables>
......@@ -46,7 +45,6 @@
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
language = ""
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
......
......@@ -25,31 +25,42 @@ class _MyAppState extends State<MyApp> {
appBar: new AppBar(
title: const Text('Plugin example app'),
),
body: new Center(
body: Container(
child: new Center(
child: new Column(
children: <Widget>[
new RaisedButton(
onPressed: () {
ShareExtend.share("share text", "text");
},
child: new Text("share text"),
children: <Widget>[
new RaisedButton(
onPressed: () {
ShareExtend.share("share text", "text");
},
child: new Text("share text"),
),
new RaisedButton(
onPressed: () async {
File f = await ImagePicker.pickImage(
source: ImageSource.gallery);
ShareExtend.share(f.path, "image");
},
child: new Text("share image"),
),
new RaisedButton(
onPressed: () async {
File f = await ImagePicker.pickVideo(
source: ImageSource.gallery);
ShareExtend.share(f.path, "video");
},
child: new Text("share video"),
),
new RaisedButton(
onPressed: () {
_shareApplicationDocumentsFile();
},
child: new Text("share file"),
),
],
),
new RaisedButton(
onPressed: () async {
File f =
await ImagePicker.pickImage(source: ImageSource.gallery);
ShareExtend.share(f.path, "image");
},
child: new Text("share image"),
),
new RaisedButton(
onPressed: () {
_shareApplicationDocumentsFile();
},
child: new Text("share file"),
),
],
)),
),
),
),
);
}
......
#import "ShareExtendPlugin.h"
@implementation FLTShareExtendPlugin
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* shareChannel = [FlutterMethodChannel
methodChannelWithName:@"share_extend"
binaryMessenger:[registrar messenger]];
[shareChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
if ([@"share" isEqualToString:call.method]) {
NSDictionary *arguments = [call arguments];
NSString *shareText = arguments[@"text"];
NSString *shareType = arguments[@"type"];
if (shareText.length == 0) {
result(
[FlutterError errorWithCode:@"error" message:@"Non-empty text expected" details:nil]);
return;
}
NSNumber *originX = arguments[@"originX"];
NSNumber *originY = arguments[@"originY"];
NSNumber *originWidth = arguments[@"originWidth"];
NSNumber *originHeight = arguments[@"originHeight"];
CGRect originRect;
if (originX != nil && originY != nil && originWidth != nil && originHeight != nil) {
originRect = CGRectMake([originX doubleValue], [originY doubleValue],
[originWidth doubleValue], [originHeight doubleValue]);
}
if ([shareType isEqualToString:@"text"]) {
[self share:shareText
withController:[UIApplication sharedApplication].keyWindow.rootViewController
atSource:originRect];
result(nil);
} else if([shareType isEqualToString:@"file"]) {
NSURL *url = [NSURL fileURLWithPath:shareText];
[self share:url
withController:[UIApplication sharedApplication].keyWindow.rootViewController
atSource:originRect];
result(nil);
} else if ([shareType isEqualToString:@"image"]) {
UIImage *image = [UIImage imageWithContentsOfFile:shareText];
[self share:image
withController:[UIApplication sharedApplication].keyWindow.rootViewController
atSource:originRect];
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar {
FlutterMethodChannel* shareChannel = [FlutterMethodChannel
methodChannelWithName:@"share_extend"
binaryMessenger:[registrar messenger]];
[shareChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
if ([@"share" isEqualToString:call.method]) {
NSDictionary *arguments = [call arguments];
NSString *shareText = arguments[@"text"];
NSString *shareType = arguments[@"type"];
if (shareText.length == 0) {
result(
[FlutterError errorWithCode:@"error" message:@"Non-empty text expected" details:nil]);
return;
}
NSNumber *originX = arguments[@"originX"];
NSNumber *originY = arguments[@"originY"];
NSNumber *originWidth = arguments[@"originWidth"];
NSNumber *originHeight = arguments[@"originHeight"];
CGRect originRect;
if (originX != nil && originY != nil && originWidth != nil && originHeight != nil) {
originRect = CGRectMake([originX doubleValue], [originY doubleValue],
[originWidth doubleValue], [originHeight doubleValue]);
}
if ([shareType isEqualToString:@"text"]) {
[self share:shareText atSource:originRect];
result(nil);
} else if ([shareType isEqualToString:@"image"]) {
UIImage *image = [UIImage imageWithContentsOfFile:shareText];
[self share:image atSource:originRect];
} else {
NSURL *url = [NSURL fileURLWithPath:shareText];
[self share:url atSource:originRect];
result(nil);
}
} else {
result(FlutterMethodNotImplemented);
}
} else {
result(FlutterMethodNotImplemented);
}
}];
}];
}
+ (void)share:(id)sharedItems
withController:(UIViewController *)controller
atSource:(CGRect)origin {
UIActivityViewController *activityViewController =
[[UIActivityViewController alloc] initWithActivityItems:@[ sharedItems ]
applicationActivities:nil];
activityViewController.popoverPresentationController.sourceView = controller.view;
if (!CGRectIsEmpty(origin)) {
activityViewController.popoverPresentationController.sourceRect = origin;
}
[controller presentViewController:activityViewController animated:YES completion:nil];
+ (void)share:(id)sharedItems atSource:(CGRect)origin {
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[sharedItems] applicationActivities:nil];
UIViewController *controller =[UIApplication sharedApplication].keyWindow.rootViewController;
activityViewController.popoverPresentationController.sourceView = controller.view;
if (!CGRectIsEmpty(origin)) {
activityViewController.popoverPresentationController.sourceRect = origin;
}
[controller presentViewController:activityViewController animated:YES completion:nil];
}
@end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment