【问题标题】:How do I share an image on iOS and Android using Flutter?如何使用 Flutter 在 iOS 和 Android 上共享图像?
【发布时间】:2017-10-26 03:40:57
【问题描述】:

我想使用 iOS 和 Android 中的标准共享对话框共享图像。下面的代码大部分来自https://pub.dartlang.org/packages/share,我用它作为起点(下面只有 Dart 和 Objective-C)。它目前仅共享文本。

我不确定下面的图像是不是最好的方法,我将如何将图像转换为 Dart 中的字节流并在 iOS 和 Android 中处理。

飞镖

static const _kShareChannel = const MethodChannel('example.test.com/share');
Future<Null> shareImage(Image image) {
  assert(image != null);
  return _kShareChannel.invokeMethod('shareImage', image);
}

目标-C

static NSString *const PLATFORM_CHANNEL = @"example.test.com/share";

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    [GeneratedPluginRegistrant registerWithRegistry:self];

    FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;

    FlutterMethodChannel *shareChannel = [FlutterMethodChannel methodChannelWithName:PLATFORM_CHANNEL
                            binaryMessenger:controller];

    [shareChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
        if ([@"shareImage" isEqualToString:call.method]) {
            [self share:call.arguments withController:[UIApplication sharedApplication].keyWindow.rootViewController];
            result(nil);
        } else {
            result([FlutterError errorWithCode:@"UNKNOWN_METHOD"
                                       message:@"Unknown share method called"
                                       details:nil]);
        }
    }];
    return [super application:application didFinishLaunchingWithOptions:launchOptions];
}

- (void)share:(id)sharedItems withController:(UIViewController *)controller {
    UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:@[ sharedItems ]
                                  applicationActivities:nil];
    [controller presentViewController:activityViewController animated:YES completion:nil];
}

【问题讨论】:

  • @DuncanJones 你到底需要什么?
  • @RémiRousselet 作为 Flutter 的新手,我不明白 Collin 的回答,也不知道如何继续。所以我想我正在寻找所涉及任务的更详细的演练;在哪里可能需要原生代码与在 Flutter 中可以实现的代码等。
  • @DuncanJones alardizabel 下面的回答对您的问题有帮助吗?我想这可以归结为:您要分享的图像的来源是什么?答案表明它来自资产。你的用例是什么?用相机拍的?通过http下载的?使用专有编解码器在内存中生成?您是否有需要编码的编码图像(jpeg、png 等)或原始光栅,或其他?如果这里的答案没有帮助,也许可以问你自己的问题。顺便说一句,这对您的 vCard 问题有帮助吗?如果不是,另一个问题...
  • @RichardHeap 答案看起来很有帮助(并且可能会获得赏金)。在我的具体情况下,我要分享的图像已经是应用程序文档目录中的一个文件,但我确信我可以自己找出剩余的空白。

标签: dart flutter


【解决方案1】:

如果图像文件被下载,我建议将其保存到 Dart 中的临时文件中。

await new File('${systemTempDir.path}/foo.jpg').create();

然后您可以调用UIActivityViewController 并使用代表图像文件的文件名的URL。这里有一些 sample code 介绍如何在非 Flutter 应用程序中执行此操作,应该可以帮助您入门。

如果您的图像文件是动态构建的(例如使用Canvas API),您可能想知道如何将ui.Image 对象编码到图像文件中。 Flutter 引擎目前不提供这样做的方法,可以修改引擎以添加该支持。你可以看看screenshot 支持是如何实现的,以获取灵感,但它不会是微不足道的。

【讨论】:

    【解决方案2】:

    下面将允许您在 iOS 上使用 UIActivityViewController 发送文件(在此示例中特别是图像),并在 Android 上作为共享意图。

    FileProvider overview (Android)

    更新pubspec.yaml 以引用您的本地图像(本例中为image.jpg)并使用path_provider 插件来访问文件系统。 https://pub.dartlang.org/packages/path_provider

    main.dart

    import 'dart:io';
    import 'dart:typed_data';
    
    import 'package:flutter/material.dart';
    import 'package:flutter/services.dart';
    import 'package:path_provider/path_provider.dart';
    
    void main() => runApp(new MyApp());
    
    class MyApp extends StatelessWidget {
      @override
      Widget build(BuildContext context) {
        return new MaterialApp(
          title: 'Share Demo',
          theme: new ThemeData(
            primarySwatch: Colors.blue,
          ),
          home: new MyHomePage(title: 'Share Demo Home Page'),
        );
      }
    }
    
    class MyHomePage extends StatefulWidget {
      MyHomePage({Key key, this.title}) : super(key: key);
    
      final String title;
    
      @override
      _MyHomePageState createState() => new _MyHomePageState();
    }
    
    class _MyHomePageState extends State<MyHomePage> {
    
      @override
      Widget build(BuildContext context) {
    
        return new Scaffold(
          appBar: new AppBar(
            title: new Text(widget.title),
          ),
          body: new Center(
            child: new Column(
              mainAxisAlignment: MainAxisAlignment.center,
              children: <Widget>[
              ],
            ),
          ),
          floatingActionButton: new FloatingActionButton(
            onPressed: _shareImage,
            tooltip: 'Share',
            child: new Icon(Icons.share),
          ),
        );
      }
    
      _shareImage() async {
        try {
          final ByteData bytes = await rootBundle.load('assets/image.jpg');
          final Uint8List list = bytes.buffer.asUint8List();
    
          final tempDir = await getTemporaryDirectory();
          final file = await new File('${tempDir.path}/image.jpg').create();
          file.writeAsBytesSync(list);
    
          final channel = const MethodChannel('channel:me.albie.share/share');
          channel.invokeMethod('shareFile', 'image.jpg');
    
        } catch (e) {
          print('Share error: $e');
        }
      }
    }
    

    AppDelegate.m

    #include "AppDelegate.h"
    #include "GeneratedPluginRegistrant.h"
    
    @implementation AppDelegate
    
    static NSString *const SHARE_CHANNEL = @"channel:me.albie.share/share";
    
    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        [GeneratedPluginRegistrant registerWithRegistry:self];
        FlutterViewController* controller = (FlutterViewController*)self.window.rootViewController;
    
        FlutterMethodChannel *shareChannel =
        [FlutterMethodChannel methodChannelWithName:SHARE_CHANNEL
                                    binaryMessenger:controller];
    
        [shareChannel setMethodCallHandler:^(FlutterMethodCall *call, FlutterResult result) {
            if ([@"shareFile" isEqualToString:call.method]) {
                [self shareFile:call.arguments
                 withController:[UIApplication sharedApplication].keyWindow.rootViewController];
            }
        }];
    
        return [super application:application didFinishLaunchingWithOptions:launchOptions];
    }
    
    - (void)shareFile:(id)sharedItems withController:(UIViewController *)controller {
        NSMutableString *filePath = [NSMutableString stringWithString:sharedItems];
        NSString *docsPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0];
        NSString *imagePath = [docsPath stringByAppendingPathComponent:filePath];
        NSURL *imageUrl = [NSURL fileURLWithPath:imagePath];
        NSData *imageData = [NSData dataWithContentsOfURL:imageUrl];
        UIImage *shareImage = [UIImage imageWithData:imageData];
    
        UIActivityViewController *activityViewController =
        [[UIActivityViewController alloc] initWithActivityItems:@[ shareImage ]
                                          applicationActivities:nil];
        [controller presentViewController:activityViewController animated:YES completion:nil];
    }
    
    @end
    

    MainActivity.java

    package com.example.share;
    
    import android.content.Intent;
    import android.net.Uri;
    import android.os.Bundle;
    
    import java.io.File;
    
    import io.flutter.app.FlutterActivity;
    import io.flutter.plugin.common.MethodCall;
    import io.flutter.plugin.common.MethodChannel;
    import io.flutter.plugins.GeneratedPluginRegistrant;
    
    import android.support.v4.content.FileProvider;
    
    public class MainActivity extends FlutterActivity {
    
        private static final String SHARE_CHANNEL = "channel:me.albie.share/share";
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            GeneratedPluginRegistrant.registerWith(this);
    
            new MethodChannel(this.getFlutterView(), SHARE_CHANNEL).setMethodCallHandler(new MethodChannel.MethodCallHandler() {
                public final void onMethodCall(MethodCall methodCall, MethodChannel.Result result) {
                    if (methodCall.method.equals("shareFile")) {
                        shareFile((String) methodCall.arguments);
                    }
                }
            });
        }
    
        private void shareFile(String path) {
            File imageFile = new File(this.getApplicationContext().getCacheDir(), path);
            Uri contentUri = FileProvider.getUriForFile(this, "me.albie.share", imageFile);
            Intent shareIntent = new Intent(Intent.ACTION_SEND);
            shareIntent.setType("image/jpg");
            shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri);
            this.startActivity(Intent.createChooser(shareIntent, "Share image using"));
        }
    }
    

    AndroidManifest.xml

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="me.albie.share"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
    

    xml/file_paths.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths>
        <cache-path name="images" path="/"/>
    </paths>
    

    build.gradle(应用程序)

    dependencies {
        ...
        implementation 'com.android.support:support-v4:27.1.1'
    }
    

    【讨论】:

    • 为什么不把所有的原生 ode 结合起来做一个 Flutter 插件呢?请这样做。像我这样的人很难 Flutter
    • 非常感谢,它对我有用。我很高兴。我现在赞成这个答案!
    • 请创建一个具有此功能的插件,没有具有该功能的插件,共享文件。对于没有IOS经验的我们来说很难。提前谢谢你。
    • 请任何人创建插件,或修复目前损坏的pub.dartlang.org/packages/advanced_share 插件。我尝试使用这个答案,但没有适当的 Android 知识,这太复杂而无法调试。
    • 当我使用你的颤振代码时,点击我的按钮时出现以下异常: MissingPluginException(No implementation found for method shareFile on channel channel:me.albie.share/share) 有谁知道怎么做解决这个问题?
    【解决方案3】:

    感谢@albert-lardizabal 上面的代码,它运行得非常完美!!我不得不把它翻译成 Swift 和 Kotlin,所以这里是代码,以防你们需要它:

    斯威夫特:

    override func application(
        _ application: UIApplication,
        didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?
        ) -> Bool {
        GeneratedPluginRegistrant.register(with: self)
    
    
        let shareChannelName = "channel:me.albie.share/share";
        let controller:FlutterViewController = self.window?.rootViewController as! FlutterViewController;
        let shareChannel:FlutterMethodChannel = FlutterMethodChannel.init(name: shareChannelName, binaryMessenger: controller);
    
        shareChannel.setMethodCallHandler({
            (call: FlutterMethodCall, result: FlutterResult) -> Void in
            if (call.method == "shareFile") {
                self.shareFile(sharedItems: call.arguments!,controller: controller);
            }
        });
    
    
        return super.application(application, didFinishLaunchingWithOptions: launchOptions)
    }
    
    func shareFile(sharedItems:Any, controller:UIViewController) {
        let filePath:NSMutableString = NSMutableString.init(string: sharedItems as! String);
        let docsPath:NSString = (NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.cachesDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)[0]) as NSString;
        let imagePath = docsPath.appendingPathComponent(filePath as String);
        let imageUrl = URL.init(fileURLWithPath: imagePath, relativeTo: nil);
        do {
            let imageData = try Data.init(contentsOf: imageUrl);
            let shareImage = UIImage.init(data: imageData);
            let activityViewController:UIActivityViewController = UIActivityViewController.init(activityItems: [shareImage!], applicationActivities: nil);
            controller.present(activityViewController, animated: true, completion: nil);
        } catch let error {
            print(error.localizedDescription);
        }
    }
    

    科特林:

        override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)
    
        MethodChannel(flutterView,"channel:me.albie.share/share").setMethodCallHandler { methodCall, _ ->
            if (methodCall.method == "shareFile") {
                shareFile(methodCall.arguments as String)
            }
        }
    }
    
    private fun shareFile(path:String) {
        val imageFile = File(this.applicationContext.cacheDir,path)
        val contentUri = FileProvider.getUriForFile(this,"me.albie.share",imageFile)
    
        val shareIntent = Intent()
        shareIntent.action = Intent.ACTION_SEND
        shareIntent.type="image/jpg"
        shareIntent.putExtra(Intent.EXTRA_STREAM, contentUri)
        startActivity(Intent.createChooser(shareIntent,"Compartir usando"))
    }
    

    【讨论】:

    • 拜托,我想问你一些关于你的代码的问题,1.你能做一个我们在yaml文件中使用的lib吗?或 2. 你可以编辑帖子以逐步显示如何在项目中工作吗?和 3. 此代码适用于本地和远程文件吗? 4.它只适用于图像或任何类型的文件?提前谢谢你..
    • 如何在whats app等社交媒体中发送带文字的图片
    【解决方案4】:

    我们将该功能放入插件中:https://pub.dartlang.org/packages/esys_flutter_share

    飞镖:

    final ByteData bytes = await rootBundle.load('assets/image1.png');
    await Share.file('esys image', 'esys.png', bytes.buffer.asUint8List(), 'image/png');
    

    【讨论】:

      【解决方案5】:

      我建议使用以下颤振插件:

      https://pub.dartlang.org/packages/share

      文字分享很简单:

      Share.share('Text I wish to share');
      

      对于图像: 更好地将图像转换为 Base64 字符串并作为字符串发送。

      【讨论】:

      • 您不能与 Flutter Share Plugin 共享 Base64 字符串。我已经尝试过了,所有发生的事情都将 Base64 字符串共享为文本:/
      【解决方案6】:

      尝试使用wc_flutter_share

      https://pub.dev/packages/wc_flutter_share

      这个插件支持分享图片、文字和主题。这个插件的独特之处在于它还支持同时共享图像和文本,这是我写这个答案时其他插件不支持的。

      【讨论】:

      • 同esys_flutter_share插件:你的flutter的iOS代码需要在swift中。
      • @AlessandroSantamaria - 与 esys_flutter_share 不同 .. 我无法让 esys 在电子邮件共享中显示主题。图像/视频/音频可以很好地用于电子邮件应用程序以及正文,但主题始终是空白的。 WcFlutterShare 适用于主题,并适用于我与之共享内容的任何应用程序,用于将图像、视频、文本和音频.. 共享到电子邮件、环聊、whatsapp、Skype 等
      【解决方案7】:

      2021年,你应该使用share_plus,官方分享插件。它可靠且易于使用。

      导入库。

      import 'package:share_plus/share_plus.dart';
      

      然后在 Dart 代码中的任意位置调用静态共享方法。

      Share.share('check out my website https://example.com');
      

      share 方法还采用一个可选的主题,将在共享到电子邮件时使用。

      Share.share('check out my website https://example.com', subject: 'Look what I made!');
      

      要共享一个或多个文件,请在 Dart 代码的任何位置调用静态 shareFiles 方法。您也可以选择传入文本和主题。

      Share.shareFiles(['${directory.path}/image.jpg'], text: 'Great picture');
      Share.shareFiles(['${directory.path}/image1.jpg', '${directory.path}/image2.jpg']);
      

      【讨论】:

        猜你喜欢
        • 2020-09-15
        • 1970-01-01
        • 1970-01-01
        • 2012-11-22
        • 2016-03-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多