Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I share an image on iOS and Android using Flutter?

Tags:

flutter

dart

I would like to share an image using the standard share dialogs in iOS and Android. The code below is mostly from https://pub.dartlang.org/packages/share which I'm using as a starting point (only Dart and Objective-C below). It currently shares only text.

Instead of Image below which I'm not sure is the best approach, how would I convert the image to a byte stream in Dart and handle in iOS and Android.

Dart

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

Objective-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]; } 
like image 491
Albert Lardizabal Avatar asked May 25 '17 13:05

Albert Lardizabal


People also ask

Does Flutter support both iOS and Android?

Flutter is an open source framework developed by Google that lets you build natively compiled, multiplatform applications from a single codebase. Flutter 3 supports six platform targets: Android, iOS, Windows, macOS, Linux, and web applications.

Does Flutter look the same on Android and iOS?

Flutter uses the Dart programming language, which is different from the JavaScript that React Native uses. Dart is easy to learn for developers who are already familiar with JavaScript. Flutter apps have a native look and feel on both Android and iOS devices, thanks to Flutter's use of the Cupertino widgets.


1 Answers

The below will allow you to send a file (specifically an image in this example) using UIActivityViewController on iOS and as a share intent on Android.

FileProvider overview (Android)

Update pubspec.yaml to reference your image if local (image.jpg in this example) and to use the path_provider plugin in order to access the file system. 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 (app)

dependencies {     ...     implementation 'com.android.support:support-v4:27.1.1' } 
like image 132
Albert Lardizabal Avatar answered Oct 07 '22 09:10

Albert Lardizabal