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]; }
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.
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.
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' }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With