這個活生生的例子會教你開發flutter插件,功能是封裝Android和iOS端的分享到facebook和twitter的flutter接口。使用的分別是兩端的系統分享功能,不須要集成facebook和twitter 的 sdk。java
例子插件網址:pub.dartlang.org/packages/fl…android
展現一下樣式:ios
ios 中分享到facebook:swift
android中分享到facebookxcode
請看原文更詳細:tryenough.com/flutter-plu…bash
開始開發插件app
這裏用的Android studio建立的項目,能夠直接建立flutter plugin項目,你也能夠用命令建立:less
flutter create --org com.example --template=plugin "plugin_name"
複製代碼
將上面的「plugin_name」換成你的插件名字就好了,我這個插件名字叫flutter_share_go,因此命令就是:async
flutter create --org com.example --template=plugin flutter_share_go
複製代碼
這裏沒有支持swift和kotlin,緣由是使用插件的不少項目可能並不支持,以避免形成沒必要要的麻煩,可是你仍然能夠選擇支持,命令以下:ide
flutter create --template=plugin -i swift -a kotlin flutter_share_go
複製代碼
查看建立好的項目結構:
**Android文件夾中:**Android端原生的代碼 **iOS文件夾中:**iOS端原生的代碼 **example文件:**是方便測試你的插件的例子代碼 **lib文件:**插件對原生接口的封裝,也就是直接在dart代碼中調用的接口
先在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();
}
}
}
複製代碼
請看原文更詳細:tryenough.com/flutter-plu…
分析一 咱們添加一個構造方法,用來存儲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
複製代碼
請看原文更詳細:tryenough.com/flutter-plu…
最後須要咱們在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
複製代碼
請看原文更詳細:tryenough.com/flutter-plu…