flutter 三方授权及简单插件维护

232 阅读3分钟

本篇简单介绍下,使用的三方授权以及简单维护的几个flutter原生插件

三方登录

苹果登录

三方库: sign_in_with_apple | Flutter Package (pub.dev)

  • Xcode内配置需要的权限

image.png

  • dart端代码实现
final credential = await SignInWithApple.getAppleIDCredential(
  scopes: [
    AppleIDAuthorizationScopes.email,
    AppleIDAuthorizationScopes.fullName,
  ],
);
final id = credential.userIdentifier;
final idToken = credential.identityToken;

facebook登录(需翻墙)

三方库: flutter_login_facebook | Flutter Package (pub.dev)

  • Xcode内配置需要的权限
<key>CFBundleURLTypes</key>
<array>
  <dict>
  <key>CFBundleURLSchemes</key>
  <array>
    <string>fb[APP_ID]</string>
  </array>
  </dict>
</array>
<key>FacebookAppID</key>
<string>[APP_ID]</string>
<key>FacebookClientToken</key>
<string>[CLIENT_TOKEN]</string>
<key>FacebookDisplayName</key>
<string>[APP_NAME]</string>
<key>LSApplicationQueriesSchemes</key>
<array>
  <string>fbapi</string>
  <string>fb-messenger-share-api</string>
</array>

配置完成后生成urltype

image.png

  • dart端代码实现,注意facebook登录需要翻墙
// 创建实例
static final FacebookLogin facebookSignIn = FacebookLogin();
// 授权
static Future<ThirdAuth> signInFacebook() async {
    final res = await facebookSignIn.logIn(
      permissions: [
        FacebookPermission.publicProfile,
        FacebookPermission.email,
      ],
    );
// Check result status
    switch (res.status) {
      case FacebookLoginStatus.success:
      // Send access token to server for validation and auth
        final FacebookAccessToken? accessToken = res.accessToken;
        final userId = accessToken?.userId;
        final token = accessToken?.token;
        if (accessToken == null || userId == null || token == null) {
          throw Exception('cancel'.tr);
        } else {
          debugPrint('user Id: $userId \n Access token: $token');
          return ThirdAuth(userId, token);
        }
      case FacebookLoginStatus.cancel:
        throw BaseException(0, 'cancel'.tr);
      case FacebookLoginStatus.error:
        debugPrint('Error while log in: ${res.error}');
        throw BaseException(0, 'error'.tr);
    }
  }

google登录(需翻墙)

google_sign_in | Flutter Package (pub.dev)

  • Xcode内配置需要的权限 这一步按照该三方库介绍一步一步按照顺序来

image.png 注意点: GoogleService-Info.plist是控制台配置完成后下载下来的,拖到xcode里面,server_client_id可以在dart端配置,就是初始化googlesignin实例的clientid实例,在iOS原生端使用的时候,原来的clientid格式是com.googleusercontent.apps.*******,但是在dart端,你需要写成********.apps.googleusercontent.com,这一点很容易忽略,而且很容易出错

// 创建实例
static final GoogleSignIn _googleSignIn = GoogleSignIn(
  clientId: Platform.isIOS
      ? '****你的授权id******'
      : '****你的授权id******',
  scopes: <String>[
    'email',
  ],
);
// 授权
static Future<ThirdAuth> signInWithGoogle() async {
  try {
    final GoogleSignInAccount? googleUser = await _googleSignIn.signIn();
    final GoogleSignInAuthentication googleAuth =
    await googleUser!.authentication;
    final idToken = googleAuth.idToken;
    final id = googleUser.id;
    if (idToken == null) {
      throw BaseException(0, 'error'.tr);
    }
    return ThirdAuth(id, idToken);
  } catch (e) {
    throw BaseException(0, 'error'.tr);
  }
}

文件上传

从这里开始,后面的都是一些自己维护的插件,flutter插件写起来还是比较容易的,iOS这边比较重要的是要会写podspec,这个还是需要认真学一下podspec的规则写法.

aws3

pub.dev中的aws3库的都不太好用,所以这里是我和安卓童鞋一起维护的plugin

这里我就只简单贴一下iOS这边的原生实现,其实也是很简单,原生的代码拖过来稍微改一下即可(原生是别人写的,我只是简单增加了个rx的拓展),设计隐私文件夹,bucket什么的就不展示了

/// 初始化配置
/// - Parameters:
///   - key:
///   - secret:
///   - region:
static func config(accessKey: String, secretKey: String, bucketRegion: String, bucketName: String) {
    let provider = AWSStaticCredentialsProvider(accessKey: accessKey, secretKey: secretKey)
    
    guard _transferUtility == nil else {
        return
    }
    guard let configuration = AWSServiceConfiguration(
        region: getAwsRegion(keyStr: bucketRegion),
        credentialsProvider: provider
    ) else {
        return
    }
    rootBucketName = bucketName
    
    let transferConfig = AWSS3TransferUtilityConfiguration()
    transferConfig.retryLimit = 3
    transferConfig.multiPartConcurrencyLimit = 10
    transferConfig.timeoutIntervalForResource = 30
    
    AWSS3TransferUtility.register(
        with: configuration,
        transferUtilityConfiguration: transferConfig,
        forKey: "transfer-utility-with-advanced-options"
    )
    _transferUtility = AWSS3TransferUtility.s3TransferUtility(forKey: "transfer-utility-with-advanced-options")
}


static func upload(
    filePath: String,
    name: String,
    bucket: String,
    contentType: String,
    progressBlock: ((Progress) -> ())?,
    success: @escaping (String) -> (),
    failure: @escaping (Error) -> ()
) {
    guard let transferUtility = _transferUtility else {
        failure(NSError(domain: "初始化未完成", code: -1))
        return
    }
    
    guard let fileURL = URL(string: filePath) else {
        failure(NSError(domain: "文件不存在", code: -1))
        return
    }
    
    let progressHandler = AWSS3TransferUtilityUploadExpression()
    progressHandler.progressBlock = { (task, progress) in
        progressBlock?(progress)
    }
    let key = bucket + "/" + name
    transferUtility.uploadFile(
        fileURL,
        bucket: rootBucketName ?? "",
        key: key,
        contentType: contentType,
        expression: progressHandler,
        completionHandler: { task, error in
            DispatchQueue.main.async {
                if let error = task.error{
                    failure(error)
                } else {
                    //AWSS3TransferUtilityUploadTask *uploadTask = task.result; Do something with uploadTask.
                    debugPrint("upl ???")
                    success(task.key)
                }
            }
        }
    )
    .continueWith { task in
        DispatchQueue.main.async {
            if let error = task.error{
                failure(error)
            }
        }
        return nil
    }
}

// 增加rx的拓展
static func upload(filePath: String,
                   name: String,
                   bucket: String,
                   contentType: String,
                   needHUD: Bool = true
) -> Single<String> {
    return Single<Void>
        .just(())
        .delay(.milliseconds(300), scheduler: MainScheduler.asyncInstance)
        .flatMap ({ _ in
            Single<String>.create { signle in
                FileUploader.upload(
                    filePath: filePath,
                    name: name,
                    bucket: bucket,
                    contentType: contentType,
                    progressBlock: { progress in
                        let percentage = Int(progress.fractionCompleted * 100)
                        debugPrint(percentage)
                    }, success: { path in
                        signle(.success(path))
                    }, failure: { error in
                        signle(.failure(error))
                    })
                return Disposables.create()
            }
        })
        .subscribe(on: MainScheduler.asyncInstance)
}

google人机安全校验(需翻墙)

这个没有android有sdk可以直接调用,iOS没有sdk,需要自己创建plugin分别维护 谷歌人机安全校验,,使用的是网上的方案,一个静态网页加载,注意一段js,这里就不贴了

IM

smartfox

IM消息通信是项目的核心,dart这边使用的是原生迁移过来的功能,然后做一层plugin抹平平台差异,这个东西用的人很少,就不细讲了,需要做的也挺多的,主要是做插件的通信,算是项目的重点,这里就不贴了,这个功能开发需要很久.

tracker

埋点也是原生维护,做迁移.