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 

請看原文更詳細:http://tryenough.com/flutter-plugin-share

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章