Flutter插件开发例子分享到facebook和twitter
请看原文更详细:http://tryenough.com/flutter-plugin-share
这个活生生的例子会教你开发flutter插件,功能是封装Android和iOS端的分享到facebook和twitter的flutter接口。使用的分别是两端的系统分享功能,不需要集成facebook和twitter 的 sdk。
例子插件网址:https://pub.dartlang.org/packages/flutter_share_go#-readme-tab-
展示一下样式:
ios 中分享到facebook:
android中分享到facebook
请看原文更详细:http://tryenough.com/flutter-plugin-share
开始开发插件
步骤一:创建插件项目
这里用的Android studio创建的项目,可以直接创建flutter plugin项目,你也可以用命令创建:
flutter create --org com.example --template=plugin "plugin_name"
将上面的“plugin_name”换成你的插件名字就行了,我这个插件名字叫flutter_share_go,所以命令就是:
flutter create --org com.example --template=plugin flutter_share_go
这里没有支持swift和kotlin,原因是使用插件的很多项目可能并不支持,以免造成不必要的麻烦,但是你仍然可以选择支持,命令如下:
flutter create --template=plugin -i swift -a kotlin flutter_share_go
查看创建好的项目结构:
Android文件夹中:Android端原生的代码
iOS文件夹中:iOS端原生的代码
example文件:是方便测试你的插件的例子代码
lib文件:插件对原生接口的封装,也就是直接在dart代码中调用的接口
分别在Android studio和xcode中编辑Android和iOS代码
先在Android studio中编写Android部分代码
用Android studio打开项目中的android文件夹,因为此时缺少flutter库依赖,需要配置一下:
在项目根目录建立一个libs文件夹,用来存放flutter库,flutter库可以到你电脑的flutter sdk路径中寻找:
/bin/cache/artifacts/engine
在engine路径下有很多的android支持库,随便拷贝一个Android平台的库到libs文件夹下,右键flutter.jar,弹出菜单选择Add As Library...。这里不用担心,我们等下设置一下让它只是编译时使用,不会打包进来。
然后点击菜单File/Project Structure...,找到flutter_text_plugin的Dependencies中,将flutter库的Scope从Implementation改成Compile Only。
开始添加Android代码
添加如下两个文件:
PackageUtils.java 工具类
package com.doglobal.flutter_share_go; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; import android.net.Uri; public class PackageUtils { public static boolean isPkgInstalled(Context context, String packageName) { if (packageName == null || "".equals(packageName)) return false; android.content.pm.ApplicationInfo info = null; try { info = context.getPackageManager().getApplicationInfo(packageName, 0); return info != null; } catch (PackageManager.NameNotFoundException e) { return false; } } public static void goDownloadPage(Context context, String pkgName) { Context app = context.getApplicationContext(); try { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + pkgName)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); app.startActivity(intent); } catch (android.content.ActivityNotFoundException anfe) { Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=" + pkgName)); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); app.startActivity(intent); } } }
ShareHelper.java 工具类
package com.doglobal.flutter_share_go; import android.app.Activity; import android.content.Intent; import android.text.TextUtils; public class ShareHelper { public static final String CHANNEL_FACEBOOK_PKG_NAME = "com.facebook.katana"; public static final String CHANNEL_TWITTER_PKG_NAME = "com.twitter.android"; public static void shareMain(Activity activity, String shareText) { shareText(activity, null, null, shareText, null, ""); } public static void shareTextToChannel(Activity activity,String pkgName, String shareText, String shareUrl) { if (PackageUtils.isPkgInstalled(activity, pkgName)) { shareText(activity, null, null, shareText, pkgName, shareUrl); } else { PackageUtils.goDownloadPage(activity, pkgName); } } /** * @param dlgTitle 选择弹框标题 * @param subject 分享主题 * @param shareText 分享内容 */ public static void shareText(Activity activity, String dlgTitle, String subject, String shareText, String pkgName, String shareUrl) { if (shareText == null || "".equals(shareText)) { return; } String content = shareText + ": " + shareUrl + " ."; Intent intent = new Intent(Intent.ACTION_SEND); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.setType("text/plain"); if (!TextUtils.isEmpty(subject)) { intent.putExtra(Intent.EXTRA_SUBJECT, subject); } intent.putExtra(Intent.EXTRA_TEXT, content); if (!TextUtils.isEmpty(pkgName)) { intent.setPackage(pkgName); } // 设置弹出框标题 if (TextUtils.isEmpty(dlgTitle)) { // 自定义标题 Intent chooser = Intent.createChooser(intent, dlgTitle); chooser.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); activity.startActivity(chooser); } else { // 系统默认标题 activity.startActivity(intent); } } }
然后在FlutterShareGoPlugin.java文件中添加调用逻辑。
这个文件就是java端对dart端的调用接口。我们先来看下代码,再进行解析:
package com.doglobal.flutter_share_go; import android.app.Activity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; import io.flutter.plugin.common.MethodChannel.MethodCallHandler; import io.flutter.plugin.common.MethodChannel.Result; import io.flutter.plugin.common.PluginRegistry.Registrar; /** FlutterShareGoPlugin */ public class FlutterShareGoPlugin implements MethodCallHandler { private Activity mActivity; //分析一 private FlutterShareGoPlugin(Activity context) { mActivity = context; } /** Plugin registration. */ public static void registerWith(Registrar registrar) { final MethodChannel channel = new MethodChannel(registrar.messenger(), "flutter_share_go"); channel.setMethodCallHandler(new FlutterShareGoPlugin(registrar.activity())); } @Override public void onMethodCall(MethodCall call, Result result) { if (call.method.equals("getPlatformVersion")) { result.success("Android " + android.os.Build.VERSION.RELEASE); } else if (call.method.equals("shareToFBPlatform")) { //分析二 String content = call.argument("shareContent"); String shareUrl = call.argument("shareUrl"); ShareHelper.shareTextToChannel(mActivity, ShareHelper.CHANNEL_FACEBOOK_PKG_NAME, content, shareUrl); } else if (call.method.equals("shareToTwitterPlatform")) { String content = call.argument("shareContent"); String shareUrl = call.argument("shareUrl"); ShareHelper.shareTextToChannel(mActivity, ShareHelper.CHANNEL_TWITTER_PKG_NAME, content, shareUrl); } else { result.notImplemented(); } } }
请看原文更详细:http://tryenough.com/flutter-plugin-share
- 分析一
我们添加一个构造方法,用来存储activity
- 分析二
在方法onMethodCall中根据dart传递过来的方法名调用java端不同的代码逻辑
至此,Android端代码就告一段落了。
iOS端开发,在xcode中开发
如图,我们在Android studio中打开一个iOS文件,在右上角会有用xcode打开的按钮,我们点击打开就可以用xcode编辑了。
打开项目添加上图中的文件:
FlutterShareGoPlugin.m文件
#import "FlutterShareGoPlugin.h" #import "ShareHelper.h" #import <Social/Social.h> @interface FlutterShareGoPlugin() @property (nonatomic, strong)UIViewController * rootViewController; @end @implementation FlutterShareGoPlugin + (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar>*)registrar { FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:@"flutter_share_go" binaryMessenger:[registrar messenger]]; FlutterShareGoPlugin* instance = [[FlutterShareGoPlugin alloc] init]; [registrar addMethodCallDelegate:instance channel:channel]; } - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result { if ([@"getPlatformVersion" isEqualToString:call.method]) { result([@"iOS " stringByAppendingString:[[UIDevice currentDevice] systemVersion]]); } else if ([@"shareToFBPlatform" isEqualToString:call.method]) { NSDictionary *arguments = [call arguments]; NSString * shareContent = arguments[@"shareContent"]; NSString * shareUrl = arguments[@"shareUrl"]; [ShareHelper shareToPlatformType:SLServiceTypeFacebook withContent:shareContent withShareUrl:shareUrl]; result(nil); } else if ([@"shareToTwitterPlatform" isEqualToString:call.method]) { NSDictionary *arguments = [call arguments]; NSString * shareContent = arguments[@"shareContent"]; NSString * shareUrl = arguments[@"shareUrl"]; [ShareHelper shareToPlatformType:SLServiceTypeTwitter withContent:shareContent withShareUrl:shareUrl]; result(nil); } else { result(FlutterMethodNotImplemented); } } @end
PackageUtil.h
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface PackageUtil : NSObject // Is intalled specific app or not + (BOOL)isInstalledWithUrlScheme:(NSString *)urlScheme; @end NS_ASSUME_NONNULL_END
PackageUtil.m
#import "PackageUtil.h" @implementation PackageUtil + (BOOL)isInstalledWithUrlScheme:(NSString *)urlScheme { if (urlScheme == nil || urlScheme.length == 0) { return false; } return [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:urlScheme]]; } @end
ShareHelper.h
#import <Foundation/Foundation.h> NS_ASSUME_NONNULL_BEGIN @interface ShareHelper : NSObject +(void)shareToPlatformType:(NSString *)platformType withContent:(NSString *)content withShareUrl:(NSString*)url; @end NS_ASSUME_NONNULL_END
ShareHelper.m
#import "ShareHelper.h" #import <Social/Social.h> #import "PackageUtil.h" @implementation ShareHelper /* SOCIAL_EXTERN NSString *const SLServiceTypeTwitter NS_AVAILABLE(10_8, 6_0);//Twitter SOCIAL_EXTERN NSString *const SLServiceTypeFacebook NS_AVAILABLE(10_8, 6_0);//Facebook SOCIAL_EXTERN NSString *const SLServiceTypeSinaWeibo NS_AVAILABLE(10_8, 6_0); SOCIAL_EXTERN NSString *const SLServiceTypeTencentWeibo NS_AVAILABLE(10_9, 7_0); SOCIAL_EXTERN NSString *const SLServiceTypeLinkedIn NS_AVAILABLE(10_9, NA); */ +(void)shareToPlatformType:(NSString *)platformType withContent:(NSString *)content withShareUrl:(NSString*)url{ if (platformType == nil || platformType.length == 0) { NSLog(@"unspecified platform"); return; } if([platformType isEqualToString:SLServiceTypeFacebook] && ![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"fb://"]]) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/app/id284882215"]]; NSLog(@"UnInstall facebook"); return; } if([platformType isEqualToString:SLServiceTypeTwitter] && ![[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"twitter://"]]) { [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"itms-apps://itunes.apple.com/app/id333903271"]]; NSLog(@"UnInstall twitter"); return; } // create controller for ServiceType SLComposeViewController *composeVC = [SLComposeViewController composeViewControllerForServiceType:platformType]; // image // [composeVC addImage:[UIImage imageNamed:@"Nameless"]]; // content [composeVC setInitialText:content]; // share url [composeVC addURL:[NSURL URLWithString:url]]; // share controller if([[[UIApplication sharedApplication] keyWindow].rootViewController isKindOfClass:[UINavigationController class]]) { UINavigationController *vc = (UINavigationController *)[[UIApplication sharedApplication] keyWindow].rootViewController; [vc pushViewController:composeVC animated:YES]; } else { UINavigationController *vc = (UINavigationController *)[[UIApplication sharedApplication] keyWindow].rootViewController; [vc presentViewController:composeVC animated:YES completion:nil]; } // callback user hanlder composeVC.completionHandler = ^(SLComposeViewControllerResult result){ if (result == SLComposeViewControllerResultDone) { } else if (result == SLComposeViewControllerResultCancelled) { } }; } @end
请看原文更详细:http://tryenough.com/flutter-plugin-share
最后需要我们在plist文件中添加白名单,用于iOS9适配,查看是否安装了facebook和twitter:
iOS 部分代码到此也告一段落了。
添加flutter接口,供dart代码调用
打开项目中lib文件夹下的flutter_share_go文件
FlutterShareGo.dart
import 'dart:async'; import 'package:flutter/services.dart'; class FlutterShareGo { static const MethodChannel _channel = const MethodChannel('flutter_share_go'); static Future<String> get platformVersion async { final String version = await _channel.invokeMethod('getPlatformVersion'); return version; } static Future<void> shareToFBPlatform(String shareContent, String shareUrl) async { assert(shareContent != null); assert(shareContent.isNotEmpty); final Map<String, dynamic> params = <String, dynamic> { 'shareContent': shareContent, 'shareUrl':shareUrl, }; await _channel.invokeMethod("shareToFBPlatform", params); } static Future<void> shareToTwitterPlatform(String shareContent, String shareUrl) async { assert(shareContent != null); assert(shareContent.isNotEmpty); final Map<String, dynamic> params = <String, dynamic> { 'shareContent': shareContent, 'shareUrl':shareUrl, }; await _channel.invokeMethod("shareToTwitterPlatform", params); } }
flutter端代码就告一段落了。
测试插件:
打开项目中example文件下的main.dart:
main.dart
import 'package:flutter/material.dart'; import 'dart:async'; import 'package:flutter/services.dart'; import 'package:flutter_share_go/flutter_share_go.dart'; void main() => runApp(MyApp()); class MyApp extends StatefulWidget { @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { String _platformVersion = 'Unknown'; @override void initState() { super.initState(); initPlatformState(); } // Platform messages are asynchronous, so we initialize in an async method. Future<void> initPlatformState() async { String platformVersion; // Platform messages may fail, so we use a try/catch PlatformException. try { platformVersion = await FlutterShareGo.platformVersion; } on PlatformException { platformVersion = 'Failed to get platform version.'; } // If the widget was removed from the tree while the asynchronous platform // message was in flight, we want to discard the reply rather than calling // setState to update our non-existent appearance. if (!mounted) return; setState(() { _platformVersion = platformVersion; }); } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('Plugin example app'), ), body: Column( children: <Widget>[ Text('Running on: $_platformVersion\n'), RaisedButton( child: Text("分享到facebook按钮"), color: Colors.red, onPressed: () { FlutterShareGo.shareToFBPlatform("test share to fb content", "http://tryenough.com"); }, ) ], ), ), ); } }
运行就会出现文章最上面的效果了。祝你顺利。
最后发布可以参照如下步骤:
运行命令,并解决所有出现的问题:
flutter packages pub publish --dry-run
问题解决完就可以发布了,命令:
flutter packages pub publish