Commit a5d75a7e authored by 汪林玲's avatar 汪林玲

Initial commit

parents
kind: pipeline
name: default
steps:
- name: prepare
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- flutter packages get
#- name: build_runner
# image: v7lin/flutter:1.17.3-stable
# volumes:
# - name: pub-cache
# path: /opt/flutter/.pub-cache
# commands:
# - flutter pub run build_runner build --delete-conflicting-outputs
#- name: android-check
# image: v7lin/flutter:1.17.3-stable
# volumes:
# - name: pub-cache
# path: /opt/flutter/.pub-cache
# - name: gradle
# path: /root/.gradle
# commands:
# - cd example/android/
# - ./gradlew :alipay_kit:check
# docker run --rm -it -v ${PWD}:/src v7lin/clang:5.0.2-r0 sh -c "clang-format -style=file -i src/Classes/*.h src/Classes/*.m"
#- name: ios-format
# image: v7lin/clang
# commands:
# - cd ios/
# - clang-format -style=file -i src/Classes/*.h src/Classes/*.m
- name: format
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- flutter format --dry-run --set-exit-if-changed .
- name: analyze
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- flutter analyze
- name: test
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- flutter test --coverage
# - cd example/
# - flutter test
- name: proguard
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
- name: gradle
path: /root/.gradle
commands:
- cd example/
- flutter build apk
- name: coverage
image: plugins/codecov:2.0.3
settings:
token:
from_secret: CODECOV_TOKEN
files:
- ./coverage/lcov.info
when:
event:
exclude:
- pull_request
- name: publish-check
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- flutter packages pub publish --dry-run
volumes:
- name: pub-cache
temp: {}
- name: gradle
temp: {}
---
kind: pipeline
name: publish
steps:
- name: restore-cache
image: alpine:3.9.3
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- FLUTTER_HOME=/opt/flutter/.pub-cache
- wget -P $FLUTTER_HOME https://raw.githubusercontent.com/v7lin/pub_credentials/master/credentials.json.enc
- name: restore-cache-openssl
image: v7lin/openssl:1.1.1b
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
environment:
ENC_METHOD:
from_secret: ENC_METHOD
ENC_PASSWORD:
from_secret: ENC_PASSWORD
commands:
- FLUTTER_HOME=/opt/flutter/.pub-cache
- openssl enc -d -$ENC_METHOD -k $ENC_PASSWORD -in $FLUTTER_HOME/credentials.json.enc -out $FLUTTER_HOME/credentials.json
- rm $FLUTTER_HOME/credentials.json.enc
- name: publish
image: v7lin/flutter:1.17.3-stable
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
commands:
- echo "y" | flutter packages pub publish
- name: save-cache-openssl
image: v7lin/openssl:1.1.1b
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
environment:
ENC_METHOD:
from_secret: ENC_METHOD
ENC_PASSWORD:
from_secret: ENC_PASSWORD
commands:
- FLUTTER_HOME=/opt/flutter/.pub-cache
- openssl enc -e -$ENC_METHOD -k $ENC_PASSWORD -in $FLUTTER_HOME/credentials.json -out $FLUTTER_HOME/credentials.json.enc
- rm /opt/flutter/.pub-cache/credentials.json
- name: save-cache
image: docker:git
volumes:
- name: pub-cache
path: /opt/flutter/.pub-cache
environment:
GIT_USER_EMAIL:
from_secret: GIT_USER_EMAIL
GIT_USER_NAME:
from_secret: GIT_USER_NAME
GIT_USER_PASSWORD:
from_secret: GIT_USER_PASSWORD # 密码含'@',用'%40'替换 -> URLEncoder.encode("@","utf-8");
commands:
- FLUTTER_HOME=/opt/flutter/.pub-cache
- git config --global user.email $GIT_USER_EMAIL
- git config --global user.name $GIT_USER_NAME
- git config --global credential.helper store
- git clone -b master https://$GIT_USER_NAME:$GIT_USER_PASSWORD@github.com/v7lin/pub_credentials.git $FLUTTER_HOME/pub_credentials
- rm $FLUTTER_HOME/pub_credentials/credentials.json.enc
- mv $FLUTTER_HOME/credentials.json.enc $FLUTTER_HOME/pub_credentials/credentials.json.enc
- cd $FLUTTER_HOME/pub_credentials
- git commit -am "update credentials by ci/cd tools"
- git push
volumes:
- name: pub-cache
temp: {}
trigger:
status:
- success
event:
- tag
depends_on:
- default
* linguist-language=Dart
\ No newline at end of file
# These are supported funding model platforms
github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
otechie: # Replace with a single Otechie username
custom: https://v7lin.github.io/docsify/#/navbar/sponsor # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
.DS_Store
.dart_tool/
.packages
.pub/
build/
# custom
.idea/
*.iml
# This file tracks properties of this Flutter project.
# Used by Flutter tool to assess capabilities and perform upgrades etc.
#
# This file should be version controlled and should not be manually edited.
version:
revision: b041144f833e05cf463b8887fa12efdec9493488
channel: stable
project_type: plugin
## 2.0.0
* 升级 Android/iOS SDK
## 2.0.0-Android-Only
* 升级 Android
* 移除 iOS 模块
## 1.1.1
* gradle 依赖兼容 4.x.x
## 1.1.0
* 优化
## 1.0.2
* 优化
## 1.0.1
* 优化 Android 依赖
* 修正 #15
## 1.0.0
* 改名 alipay_kit
* 升级 Android/iOS SDK
## 0.2.3
* 删除RSA2对密钥长度的检查
## 0.2.2
* 简化
## 0.2.1
* 修正线程安全
## 0.2.0
* 优化
* 自动化发布
## 0.1.1
* BUG 修复
## 0.1.0
* 规范 library 代码
## 0.0.1
* android/ios alipay
This diff is collapsed.
# alipay_kit
[![Build Status](https://cloud.drone.io/api/badges/v7lin/alipay_kit/status.svg)](https://cloud.drone.io/v7lin/alipay_kit)
[![Codecov](https://codecov.io/gh/v7lin/alipay_kit/branch/master/graph/badge.svg)](https://codecov.io/gh/v7lin/alipay_kit)
[![GitHub Tag](https://img.shields.io/github/tag/v7lin/alipay_kit.svg)](https://github.com/v7lin/alipay_kit/releases)
[![Pub Package](https://img.shields.io/pub/v/alipay_kit.svg)](https://pub.dartlang.org/packages/alipay_kit)
[![License](https://img.shields.io/badge/License-Apache%202.0-blue.svg)](https://github.com/v7lin/alipay_kit/blob/master/LICENSE)
flutter版支付宝SDK
## fake 系列 libraries
* [flutter版微信SDK](https://github.com/v7lin/wechat_kit)
* [flutter版腾讯(QQ)SDK](https://github.com/v7lin/tencent_kit)
* [flutter版新浪微博SDK](https://github.com/v7lin/weibo_kit)
* [flutter版支付宝SDK](https://github.com/v7lin/alipay_kit)
* [flutter版walle渠道打包工具](https://github.com/v7lin/walle_kit)
## dart/flutter 私服
* [simple_pub_server](https://github.com/v7lin/simple_pub_server)
## docs
* [蚂蚁金服开放平台](https://openhome.alipay.com/platform/appManage.htm)
* [支付宝支付](https://docs.open.alipay.com/204/105051/)
* [支付宝登录](https://docs.open.alipay.com/218/105329/)
* [应用签名工具](https://opendocs.alipay.com/open/common/104062)
## android
```
# 不需要做任何额外接入工作
# 混淆已打入 Library,随 Library 引用,自动添加到 apk 打包混淆
```
## ios
```
在Xcode中,选择你的工程设置项,选中“TARGETS”一栏,在“info”标签栏的“URL type“添加“URL scheme”为你所注册的应用程序id
URL Types
alipay: identifier=alipay schemes=${your app scheme name} # schemes 不能为纯数字,推荐:alipay${appId}
```
```
iOS 9系统策略更新,限制了http协议的访问,此外应用需要在“Info.plist”中将要使用的URL Schemes列为白名单,才可正常检查其他应用是否安装。
<key>LSApplicationQueriesSchemes</key>
<array>
<string>alipay</string>
</array>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
```
## flutter
* snapshot
```
dependencies:
alipay_kit:
git:
url: https://github.com/v7lin/alipay_kit.git
```
* release
```
dependencies:
alipay_kit: ^${latestTag}
```
```
dependencies:
# 请不要进行配置 iOS 相关配置,否则 Apple Store 审核时会拒绝
alipay_kit: ^${latestTag}-Android-Only
```
* example
[示例](./example/lib/main.dart)
## Getting Started
This project is a starting point for a Flutter
[plug-in package](https://flutter.dev/developing-packages/),
a specialized package that includes platform-specific implementation code for
Android and/or iOS.
For help getting started with Flutter, view our
[online documentation](https://flutter.dev/docs), which offers tutorials,
samples, guidance on mobile development, and a full API reference.
*.iml
.gradle
/local.properties
/.idea/workspace.xml
/.idea/libraries
.DS_Store
/build
/captures
group 'io.github.v7lin.alipay_kit'
version '2.0.0'
buildscript {
repositories {
maven{
allowInsecureProtocol = true
url 'http://127.0.0.1:8081/repository/maven-public/'
}
google()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.5.4'
}
}
rootProject.allprojects {
repositories {
maven{
allowInsecureProtocol = true
url 'http://127.0.0.1:8081/repository/maven-public/'
}
google()
}
}
apply plugin: 'com.android.library'
android {
compileSdkVersion 28
defaultConfig {
minSdkVersion 16
// library 混淆 -> 随 library 引用,自动添加到 apk 打包混淆
consumerProguardFiles 'consumer-rules.pro'
}
lintOptions {
disable 'InvalidPackage'
}
flavorDimensions 'vendor'
productFlavors {
vendor {
dimension 'vendor'
// library 混淆 -> 随 library 引用,自动添加到 apk 打包混淆
consumerProguardFiles 'consumer-vendor-rules.pro'
}
}
}
dependencies {
implementation 'androidx.annotation:annotation:1.0.0'
implementation 'com.qiaomeng:noutdid.alipaysdk:1.0.0@aar'
// v15.8.01
//vendorImplementation(name: 'alipaysdk-15.8.01.210112203525', ext: 'aar')
}
org.gradle.jvmargs=-Xmx1536M
android.enableR8=true
android.useAndroidX=true
android.enableJetifier=true
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-5.6.2-all.zip
rootProject.name = 'alipay_kit'
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.v7lin.alipay_kit">
</manifest>
package io.github.v7lin.alipay_kit;
import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.os.AsyncTask;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.alipay.sdk.app.AuthTask;
import com.alipay.sdk.app.PayTask;
import java.lang.ref.WeakReference;
import java.util.Map;
import io.flutter.plugin.common.BinaryMessenger;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
public class AlipayKit implements MethodChannel.MethodCallHandler {
//
private static final String METHOD_ISINSTALLED = "isInstalled";
private static final String METHOD_PAY = "pay";
private static final String METHOD_AUTH = "auth";
private static final String METHOD_ONPAYRESP = "onPayResp";
private static final String METHOD_ONAUTHRESP = "onAuthResp";
private static final String ARGUMENT_KEY_ORDERINFO = "orderInfo";
private static final String ARGUMENT_KEY_AUTHINFO = "authInfo";
private static final String ARGUMENT_KEY_ISSHOWLOADING = "isShowLoading";
//
private Context applicationContext;
private Activity activity;
private MethodChannel channel;
public AlipayKit() {
super();
}
public AlipayKit(Context applicationContext, Activity activity) {
this.applicationContext = applicationContext;
this.activity = activity;
}
//
public void setApplicationContext(@Nullable Context applicationContext) {
this.applicationContext = applicationContext;
}
public void setActivity(@Nullable Activity activity) {
this.activity = activity;
}
public void startListening(@NonNull BinaryMessenger messenger) {
channel = new MethodChannel(messenger, "v7lin.github.io/alipay_kit");
channel.setMethodCallHandler(this);
}
public void stopListening() {
channel.setMethodCallHandler(null);
channel = null;
}
// --- MethodCallHandler
@Override
public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result) {
if (METHOD_ISINSTALLED.equals(call.method)) {
boolean isInstalled = false;
try {
final PackageManager packageManager = applicationContext.getPackageManager();
PackageInfo info = packageManager.getPackageInfo("com.eg.android.AlipayGphone", PackageManager.GET_SIGNATURES);
isInstalled = info != null;
} catch (PackageManager.NameNotFoundException e) {
}
result.success(isInstalled);
} else if (METHOD_PAY.equals(call.method)) {
final String orderInfo = call.argument(ARGUMENT_KEY_ORDERINFO);
final boolean isShowLoading = call.argument(ARGUMENT_KEY_ISSHOWLOADING);
final WeakReference<Activity> activityRef = new WeakReference<>(activity);
final WeakReference<MethodChannel> channelRef = new WeakReference<>(channel);
new AsyncTask<String, String, Map<String, String>>() {
@Override
protected Map<String, String> doInBackground(String... params) {
Activity activity = activityRef.get();
if (activity != null && !activity.isFinishing()) {
PayTask task = new PayTask(activity);
return task.payV2(orderInfo, isShowLoading);
}
return null;
}
@Override
protected void onPostExecute(Map<String, String> result) {
if (result != null) {
Activity activity = activityRef.get();
MethodChannel channel = channelRef.get();
if (activity != null && !activity.isFinishing() && channel != null) {
channel.invokeMethod(METHOD_ONPAYRESP, result);
}
}
}
}.execute();
result.success(null);
} else if (METHOD_AUTH.equals(call.method)) {
final String authInfo = call.argument(ARGUMENT_KEY_AUTHINFO);
final boolean isShowLoading = call.argument(ARGUMENT_KEY_ISSHOWLOADING);
final WeakReference<Activity> activityRef = new WeakReference<>(activity);
final WeakReference<MethodChannel> channelRef = new WeakReference<>(channel);
new AsyncTask<String, String, Map<String, String>>(){
@Override
protected Map<String, String> doInBackground(String... strings) {
Activity activity = activityRef.get();
if (activity != null && !activity.isFinishing()) {
AuthTask task = new AuthTask(activity);
return task.authV2(authInfo, isShowLoading);
}
return null;
}
@Override
protected void onPostExecute(Map<String, String> result) {
if (result != null) {
Activity activity = activityRef.get();
MethodChannel channel = channelRef.get();
if (activity != null && !activity.isFinishing() && channel != null) {
channel.invokeMethod(METHOD_ONAUTHRESP, result);
}
}
}
}.execute();
result.success(null);
} else {
result.notImplemented();
}
}
}
package io.github.v7lin.alipay_kit;
import androidx.annotation.NonNull;
import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.embedding.engine.plugins.activity.ActivityAware;
import io.flutter.embedding.engine.plugins.activity.ActivityPluginBinding;
import io.flutter.plugin.common.PluginRegistry.Registrar;
/**
* AlipayKitPlugin
*/
public class AlipayKitPlugin implements FlutterPlugin, ActivityAware {
// This static function is optional and equivalent to onAttachedToEngine. It supports the old
// pre-Flutter-1.12 Android projects. You are encouraged to continue supporting
// plugin registration via this function while apps migrate to use the new Android APIs
// post-flutter-1.12 via https://flutter.dev/go/android-project-migration.
//
// It is encouraged to share logic between onAttachedToEngine and registerWith to keep
// them functionally equivalent. Only one of onAttachedToEngine or registerWith will be called
// depending on the user's project. onAttachedToEngine or registerWith must both be defined
// in the same class.
public static void registerWith(Registrar registrar) {
AlipayKit alipayKit = new AlipayKit(registrar.context(), registrar.activity());
alipayKit.startListening(registrar.messenger());
}
// --- FlutterPlugin
private final AlipayKit alipayKit;
public AlipayKitPlugin() {
alipayKit = new AlipayKit();
}
@Override
public void onAttachedToEngine(@NonNull FlutterPluginBinding binding) {
alipayKit.setApplicationContext(binding.getApplicationContext());
alipayKit.setActivity(null);
alipayKit.startListening(binding.getBinaryMessenger());
}
@Override
public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
alipayKit.stopListening();
alipayKit.setActivity(null);
alipayKit.setApplicationContext(null);
}
// --- ActivityAware
@Override
public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) {
alipayKit.setActivity(binding.getActivity());
}
@Override
public void onDetachedFromActivityForConfigChanges() {
onDetachedFromActivity();
}
@Override
public void onReattachedToActivityForConfigChanges(@NonNull ActivityPluginBinding binding) {
onAttachedToActivity(binding);
}
@Override
public void onDetachedFromActivity() {
alipayKit.setActivity(null);
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="io.github.v7lin.alipay_kit">
<queries>
<!-- targetSdkVersion>=30 -> Android 11 软件包可见性 -->
<package android:name="com.eg.android.AlipayGphone" />
</queries>
</manifest>
# 基础样式
BasedOnStyle: LLVM
# 缩进宽度
IndentWidth: 4
# 圆括号的换行方式
BreakBeforeBraces: Attach
# 是否允许循环单行
AllowShortLoopsOnASingleLine: false
# 支持一行的if
AllowShortIfStatementsOnASingleLine: false
# switch的case缩进
IndentCaseLabels: true
# 针对OC的block的缩进宽度
ObjCBlockIndentWidth: 4
# 针对OC,属性名后加空格
ObjCSpaceAfterProperty: true
# 每行字符的长度
ColumnLimit: 0
# 注释对齐
AlignTrailingComments: true
# 括号后加空格
SpaceAfterCStyleCast: false
# 不在小括号里加空格
SpacesInParentheses: false
# 不在中括号里加空格
SpacesInSquareBrackets: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: false
.idea/
.vagrant/
.sconsign.dblite
.svn/
.DS_Store
*.swp
profile
DerivedData/
build/
GeneratedPluginRegistrant.h
GeneratedPluginRegistrant.m
.generated/
*.pbxuser
*.mode1v3
*.mode2v3
*.perspectivev3
!default.pbxuser
!default.mode1v3
!default.mode2v3
!default.perspectivev3
xcuserdata
*.moved-aside
*.pyc
*sync/
Icon?
.tags*
/Flutter/Generated.xcconfig
/Flutter/flutter_export_environment.sh
\ No newline at end of file
#import <Flutter/Flutter.h>
@interface AlipayKitPlugin : NSObject <FlutterPlugin>
@end
#import "AlipayKitPlugin.h"
#import <AlipaySDK/AlipaySDK.h>
@implementation AlipayKitPlugin {
FlutterMethodChannel *_channel;
}
+ (void)registerWithRegistrar:(NSObject<FlutterPluginRegistrar> *)registrar {
FlutterMethodChannel *channel = [FlutterMethodChannel
methodChannelWithName:@"v7lin.github.io/alipay_kit"
binaryMessenger:[registrar messenger]];
AlipayKitPlugin *instance = [[AlipayKitPlugin alloc] initWithChannel:channel];
[registrar addApplicationDelegate:instance];
[registrar addMethodCallDelegate:instance channel:channel];
}
static NSString *const METHOD_ISINSTALLED = @"isInstalled";
static NSString *const METHOD_PAY = @"pay";
static NSString *const METHOD_AUTH = @"auth";
static NSString *const METHOD_ONPAYRESP = @"onPayResp";
static NSString *const METHOD_ONAUTHRESP = @"onAuthResp";
static NSString *const ARGUMENT_KEY_ORDERINFO = @"orderInfo";
static NSString *const ARGUMENT_KEY_AUTHINFO = @"authInfo";
static NSString *const ARGUMENT_KEY_ISSHOWLOADING = @"isShowLoading";
- (instancetype)initWithChannel:(FlutterMethodChannel *)channel {
self = [super init];
if (self) {
_channel = channel;
}
return self;
}
- (void)handleMethodCall:(FlutterMethodCall *)call result:(FlutterResult)result {
if ([METHOD_ISINSTALLED isEqualToString:call.method]) {
BOOL isInstalled = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:@"alipay:"]];
result([NSNumber numberWithBool:isInstalled]);
} else if ([METHOD_PAY isEqualToString:call.method]) {
NSString *orderInfo = call.arguments[ARGUMENT_KEY_ORDERINFO];
// NSNumber * isShowLoading = call.arguments[ARGUMENT_KEY_ISSHOWLOADING];
NSString *scheme = [self fetchUrlScheme];
[[AlipaySDK defaultService] payOrder:orderInfo
fromScheme:scheme
callback:^(NSDictionary *resultDic) {
[self->_channel invokeMethod:METHOD_ONPAYRESP arguments:resultDic];
}];
result(nil);
} else if ([METHOD_AUTH isEqualToString:call.method]) {
NSString *authInfo = call.arguments[ARGUMENT_KEY_AUTHINFO];
// NSNumber * isShowLoading = call.arguments[ARGUMENT_KEY_ISSHOWLOADING];
NSString *scheme = [self fetchUrlScheme];
[[AlipaySDK defaultService] auth_V2WithInfo:authInfo
fromScheme:scheme
callback:^(NSDictionary *resultDic) {
[self->_channel invokeMethod:METHOD_ONAUTHRESP arguments:resultDic];
}];
result(nil);
} else {
result(FlutterMethodNotImplemented);
}
}
- (NSString *)fetchUrlScheme {
NSDictionary *infoDic = [[NSBundle mainBundle] infoDictionary];
NSArray *types = [infoDic objectForKey:@"CFBundleURLTypes"];
for (NSDictionary *type in types) {
if ([@"alipay" isEqualToString:[type objectForKey:@"CFBundleURLName"]]) {
return [type objectForKey:@"CFBundleURLSchemes"][0];
}
}
return nil;
}
#pragma mark - AppDelegate
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation {
return [self handleOpenURL:url];
}
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey, id> *)options {
return [self handleOpenURL:url];
}
- (BOOL)handleOpenURL:(NSURL *)url {
if ([url.host isEqualToString:@"safepay"]) {
// 支付跳转支付宝钱包进行支付,处理支付结果
__weak typeof(self) weakSelf = self;
[[AlipaySDK defaultService] processOrderWithPaymentResult:url
standbyCallback:^(NSDictionary *resultDic) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf->_channel invokeMethod:METHOD_ONPAYRESP arguments:resultDic];
}];
// 授权跳转支付宝钱包进行支付,处理支付结果
[[AlipaySDK defaultService] processAuth_V2Result:url
standbyCallback:^(NSDictionary *resultDic) {
__strong typeof(weakSelf) strongSelf = weakSelf;
[strongSelf->_channel invokeMethod:METHOD_ONAUTHRESP arguments:resultDic];
}];
return YES;
}
return NO;
}
@end
!function(){if(!window.AlipayJSBridge){window.alipayjsbridgeSetTitle=function(e){document.title=e,t("alipayjsbridge://setTitle?title="+encodeURIComponent(e))},window.alipayjsbridgeRefresh=function(){t("alipayjsbridge://onRefresh?")},window.alipayjsbridgeBack=function(){t("alipayjsbridge://onBack?")},window.alipayjsbridgeExit=function(e){t("alipayjsbridge://onExit?bsucc="+e)},window.alipayjsbridgeShowBackButton=function(e){t("alipayjsbridge://showBackButton?bshow="+e)},window.AlipayJSBridge={version:"2.0",addListener:function(e,i){a[e]=i},hasListener:function(e){if(!a[e])return!1;return!0},callListener:function(e,i,n){var t;n&&(t=function(e){var i="";e&&(i=encodeURIComponent(JSON.stringify(e)));var a="func=h5JsFuncCallback&cbId="+n+"&data="+i;o(a)});var r=a[e];r?r(i,t):console.log("AlipayJSBridge: no h5JsFunc ",e+i)},callNativeFunc:function(e,a,t){var r="";t&&(r="cb_"+i+++"_"+(new Date).getTime(),n[r]=t);var d="";a&&(d=encodeURIComponent(JSON.stringify(a)));o("func="+e+"&cbId="+r+"&data="+d)},callBackFromNativeFunc:function(e,i){var a=n[e];a&&(a(i),delete n[i])}};var e,i=1,n={},a={};window.CustomEvent?e=new CustomEvent("alipayjsbridgeready"):(e=document.createEvent("Event")).initEvent("alipayjsbridgeready",!0,!0),document.dispatchEvent(e),setTimeout(function(){if(window.AlipayJSBridgeInitArray){var e=window.AlipayJSBridgeInitArray;delete window.AlipayJSBridgeInitArray;for(var i=0;i<e.length;i++)try{e[i](AlipayJSBridge)}catch(e){setTimeout(function(){throw e})}}},0)}function t(e){window.webkit&&window.webkit.messageHandlers&&window.webkit.messageHandlers.MQPJSBridgeScheme&&window.webkit.messageHandlers.MQPJSBridgeScheme.postMessage&&window.webkit.messageHandlers.MQPJSBridgeScheme.postMessage(e)}function o(e){t("alipayjsbridge://callNativeFunc?"+e)}}();
//
// AFServiceCenter.h
// AFServiceSDK
//
// Created by jiajunchen on 02/01/2018.
// Copyright © 2018 antfin. All rights reserved.
//
#import <Foundation/Foundation.h>
@class AFServiceResponse;
/**
SDK支持的业务枚举值
- AFServiceEInvoice: 电子发票
- AFServiceAuth: 账户授权
*/
typedef NS_ENUM(NSUInteger, AFService) {
AFServiceEInvoice,
AFServiceAuth,
AFServiceDeduct
};
extern NSString * const kAFServiceOptionBizParams; // 钱包服务调用入参
extern NSString * const kAFServiceOptionCallbackScheme; // 业务回跳当前app的scheme
extern NSString * const kAFServiceOptionNotUseLanding; // 不使用支付宝提示下载页做补偿,为true时需要商户自己处理用户未安装支付宝的情况
extern NSString * const kAFServiceBizParamsKeyUrl; // 独立签约入参url
typedef void(^AFServiceResultBlock)(AFServiceResponse *response);
@interface AFServiceCenter : NSObject
/**
调用钱包服务
@param service 业务service, 见AFService枚举值
@param params 参数Dictionary, key值详情参见kAFServiceOptionBizParams、kAFServiceOptionCallbackScheme注释
@param block 业务结果回调的block, block参数是AFServiceResponse类型,业务结果通过result属性获取,如果未用户未安装支付宝并且kAFServiceOptionNotUseLanding未设置为true,会使用H5landing页做补偿,这种情况下不会有block回调结果。
*/
+ (void)callService:(AFService)service
withParams:(NSDictionary *)params
andCompletion:(AFServiceResultBlock)block;
/**
处理钱包服务回跳APP的URL
@param url 回跳URL
@param block 业务结果回掉的block,详情见调用接口入参上的block。注意此接口上的block只有在跳转钱包后,当前APP被系统回收的情况下回跳才生效
*/
+ (void)handleResponseURL:(NSURL *)url
withCompletion:(AFServiceResultBlock)block;
@end
//
// AFServiceResponse.h
// AFServiceSDK
//
// Created by jiajunchen on 08/01/2018.
// Copyright © 2018 antfin. All rights reserved.
//
#import <Foundation/Foundation.h>
/**
钱包服务调用结果状态吗
- AFResSuccess: 默认值,业务调用成功,结果数据参见result字段
- AFResInvalidService: service枚举值错误
- AFResInvalidURL: 钱包回跳URL错误
- AFResRepeatCall: 业务重复调用(3s内)
- AFResOpenURLErr: 跳转失败
*/
typedef NS_ENUM(NSUInteger, AFResCode) {
AFResSuccess = 0,
AFResInvalidService = 100,
AFResInvalidURL,
AFResRepeatCall,
AFResOpenURLErr,
};
@interface AFServiceResponse : NSObject
/**
业务调用状态吗
*/
@property (nonatomic, assign) AFResCode responseCode;
/**
业务结果Dictionary, 内容请参考具体业务方接入文档
*/
@property (readonly) NSDictionary *result;
@end
//
// APAuthInfo.h
// APAuth
//
// Created by antfin on 17-10-24.
// Copyright (c) 2017年 AntFin. All rights reserved.
//
#import <Foundation/Foundation.h>
@interface APayAuthInfo : NSObject
@property(nonatomic, copy)NSString *appID;
@property(nonatomic, copy)NSString *pid;
@property(nonatomic, copy)NSString *redirectUri;
/**
* 初始化AuthInfo
*
* @param appIDStr 应用ID
* @param pidStr 商户ID 可不填
* @param uriStr 授权的应用回调地址 比如:alidemo://auth
*
* @return authinfo实例
*/
- (id)initWithAppID:(NSString *)appIDStr
pid:(NSString *)pidStr
redirectUri:(NSString *)uriStr;
- (NSString *)description;
- (NSString *)wapDescription;
@end
//
// AlipaySDK.h
// AlipaySDK
//
// Created by antfin on 17-10-24.
// Copyright (c) 2017年 AntFin. All rights reserved.
//
////////////////////////////////////////////////////////
///////////////// 支付宝标准版本支付SDK ///////////////////
///////// version:15.8.01 motify:2020.12.14///////////
////////////////////////////////////////////////////////
#import <UIKit/UIKit.h>
#import "APayAuthInfo.h"
#import "AFServiceCenter.h"
#import "AFServiceResponse.h"
typedef void(^CompletionBlock)(NSDictionary *resultDic);
typedef enum {
ALIPAY_TIDFACTOR_IMEI,
ALIPAY_TIDFACTOR_IMSI,
ALIPAY_TIDFACTOR_TID,
ALIPAY_TIDFACTOR_CLIENTKEY,
ALIPAY_TIDFACTOR_VIMEI,
ALIPAY_TIDFACTOR_VIMSI,
ALIPAY_TIDFACTOR_CLIENTID,
ALIPAY_TIDFACTOR_APDID,
ALIPAY_TIDFACTOR_MAX
} AlipayTidFactor;
@interface AlipaySDK : NSObject
/**
* 创建支付单例服务
*
* @return 返回单例对象
*/
+ (AlipaySDK *)defaultService;
/**
* 用于设置SDK使用的window,如果没有自行创建window无需设置此接口
*/
@property (nonatomic, weak) UIWindow *targetWindow;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝支付相关接口/////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 支付接口
*
* @param orderStr 支付订单信息字串
* @param schemeStr 调用支付的app注册在info.plist中的scheme
* @param completionBlock 支付结果回调Block,用于wap支付结果回调
跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock
*/
- (void)payOrder:(NSString *)orderStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
/**
* 支付接口 v2
*
* @param orderStr 支付订单信息字串
* @param dynamicLaunch 是否使用动态配置策略跳转支付宝支付
* @param schemeStr 调用支付的app注册在info.plist中的scheme
* @param completionBlock 支付结果回调Block,用于wap支付结果回调
跳转支付宝支付时只有当processOrderWithPaymentResult接口的completionBlock为nil时会使用这个bolock
*/
- (void)payOrder:(NSString *)orderStr
dynamicLaunch:(BOOL)dynamicLaunch
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
/**
* 处理支付宝app支付后跳回商户app携带的支付结果Url
*
* @param resultUrl 支付宝app返回的支付结果url
* @param completionBlock 支付结果回调 为nil时默认使用支付接口的completionBlock
*/
- (void)processOrderWithPaymentResult:(NSURL *)resultUrl
standbyCallback:(CompletionBlock)completionBlock;
/**
* 获取交易token。
*
* @return 交易token,若无则为空。
*/
- (NSString *)fetchTradeToken;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝授权 2.0 相关接口////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 快登授权2.0
*
* @param infoStr 授权请求信息字串
* @param schemeStr 调用授权的app注册在info.plist中的scheme
* @param completionBlock 授权结果回调,需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果
* 若在授权过程中,调用方应用被系统终止则此block无效(此时会调用'processAuth_V2Result:standbyCallback:'传入的standbyCallback)
*/
- (void)auth_V2WithInfo:(NSString *)infoStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
/**
* 处理支付宝app授权后跳回商户app携带的授权结果Url
*
* @param resultUrl 支付宝app返回的授权结果url
* @param completionBlock 授权结果回调,用于处理跳转支付宝授权过程中商户APP被系统终止的情况
*/
- (void)processAuth_V2Result:(NSURL *)resultUrl
standbyCallback:(CompletionBlock)completionBlock;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝授权 1.0 相关接口////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 快登授权
* @param authInfo 授权相关信息
* @param completionBlock 授权结果回调,若在授权过程中,调用方应用被系统终止,则此block无效,
需要调用方在appDelegate中调用processAuth_V2Result:standbyCallback:方法获取授权结果
*/
- (void)authWithInfo:(APayAuthInfo *)authInfo
callback:(CompletionBlock)completionBlock;
/**
* 处理支付宝app授权后跳回商户app携带的授权结果Url
*
* @param resultUrl 支付宝app返回的授权结果url
* @param completionBlock 授权结果回调
*/
- (void)processAuthResult:(NSURL *)resultUrl
standbyCallback:(CompletionBlock)completionBlock;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝 h5 支付转 native 支付接口////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 从h5链接中获取订单串并支付接口(自版本15.4.0起,推荐使用该接口)
*
* @param urlStr 拦截的 url string
*
* @return YES为成功获取订单信息并发起支付流程;NO为无法获取订单信息,输入url是普通url
*/
- (BOOL)payInterceptorWithUrl:(NSString *)urlStr
fromScheme:(NSString *)schemeStr
callback:(CompletionBlock)completionBlock;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝 tid 相关信息获取接口/////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 获取当前tid相关信息
*
* @return tid相关信息
*/
- (NSString*)queryTidFactor:(AlipayTidFactor)factor;
//////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////支付宝支付环境相关信息接口//////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
/**
* 是否已经使用过
*
* @return YES为已经使用过,NO反之
*/
- (BOOL)isLogined;
/**
* 获取当前版本号
*
* @return 当前版本字符串
*/
- (NSString *)currentVersion;
/**
* 測試所用,realse包无效
*
* @param url 测试环境
*/
- (void)setUrl:(NSString *)url;
/**
* 支付前主动更新本地配置
*
* @param block 更新请求结果回调
*/
- (void)fetchSdkConfigWithBlock:(void(^)(BOOL success))block;
typedef void(^APLogBlock)(NSString *log);
/**
* 接收AlipaySDK的log信息
*
* @param logBlock 打印log的回调block
*/
+ (void)startLogWithBlock:(APLogBlock)logBlock;
/**
* 停止输出log,会释放logBlock
*
*
*/
+ (void)stopLog;
@end
#
# To learn more about a Podspec see http://guides.cocoapods.org/syntax/podspec.html.
# Run `pod lib lint alipay_kit.podspec' to validate before publishing.
#
Pod::Spec.new do |s|
s.name = 'alipay_kit'
s.version = '2.0.0'
s.summary = 'A powerful Flutter plugin allowing developers to auth/pay with natvie Android & iOS Alipay SDKs.'
s.description = <<-DESC
A powerful Flutter plugin allowing developers to auth/pay with natvie Android & iOS Alipay SDKs.
DESC
s.homepage = 'http://example.com'
s.license = { :file => '../LICENSE' }
s.author = { 'Your Company' => 'email@example.com' }
s.source = { :path => '.' }
s.source_files = 'Classes/**/*'
s.public_header_files = 'Classes/**/*.h'
s.dependency 'Flutter'
s.platform = :ios, '8.0'
# v15.8.01
s.subspec 'vendor' do |sp|
sp.resources = "Libraries/*.bundle"
sp.vendored_frameworks = 'Libraries/*.framework'
sp.frameworks = 'SystemConfiguration', 'CoreTelephony', 'QuartzCore', 'CoreText', 'CoreGraphics', 'UIKit', 'Foundation', 'CFNetwork', 'CoreMotion', 'WebKit'
sp.libraries = 'c++', 'z'
end
# Flutter.framework does not contain a i386 slice. Only x86_64 simulators are supported.
s.pod_target_xcconfig = { 'DEFINES_MODULE' => 'YES', 'VALID_ARCHS[sdk=iphonesimulator*]' => 'x86_64' }
end
library alipay_kit;
export 'src/alipay.dart';
export 'src/model/alipay_auth_result.dart';
export 'src/model/alipay_resp.dart';
import 'dart:async';
import 'dart:convert';
import 'package:alipay_kit/src/crypto/rsa.dart';
import 'package:alipay_kit/src/model/alipay_resp.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/services.dart';
///
class Alipay {
///
Alipay() {
_channel.setMethodCallHandler(_handleMethod);
}
static const String _METHOD_ISINSTALLED = 'isInstalled';
static const String _METHOD_PAY = 'pay';
static const String _METHOD_AUTH = 'auth';
static const String _METHOD_ONPAYRESP = 'onPayResp';
static const String _METHOD_ONAUTHRESP = 'onAuthResp';
static const String _ARGUMENT_KEY_ORDERINFO = 'orderInfo';
static const String _ARGUMENT_KEY_AUTHINFO = 'authInfo';
static const String _ARGUMENT_KEY_ISSHOWLOADING = 'isShowLoading';
static const String SIGNTYPE_RSA = 'RSA';
static const String SIGNTYPE_RSA2 = 'RSA2';
static const String AUTHTYPE_AUTHACCOUNT = 'AUTHACCOUNT';
static const String AUTHTYPE_LOGIN = 'LOGIN';
final MethodChannel _channel =
const MethodChannel('v7lin.github.io/alipay_kit');
final StreamController<AlipayResp> _payRespStreamController =
StreamController<AlipayResp>.broadcast();
final StreamController<AlipayResp> _authRespStreamController =
StreamController<AlipayResp>.broadcast();
Future<dynamic> _handleMethod(MethodCall call) async {
switch (call.method) {
case _METHOD_ONPAYRESP:
_payRespStreamController.add(AlipayResp.fromJson(
(call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>()));
break;
case _METHOD_ONAUTHRESP:
_authRespStreamController.add(AlipayResp.fromJson(
(call.arguments as Map<dynamic, dynamic>).cast<String, dynamic>()));
break;
}
}
/// 支付
Stream<AlipayResp> payResp() {
return _payRespStreamController.stream;
}
/// 登录
Stream<AlipayResp> authResp() {
return _authRespStreamController.stream;
}
/// 检测支付宝是否已安装 - x.y.z-Android-Only 版本下 iOS 调用会直接抛出异常 No implementation [MissingPluginException]
Future<bool> isInstalled() {
return _channel.invokeMethod<bool>(_METHOD_ISINSTALLED);
}
/// 支付
Future<void> payOrderJson({
@required String orderInfo,
String signType = SIGNTYPE_RSA2,
@required String privateKey,
bool isShowLoading = true,
}) {
assert(orderInfo?.isNotEmpty ?? false);
assert(privateKey?.isNotEmpty ?? false);
return payOrderMap(
orderInfo: json.decode(orderInfo) as Map<String, dynamic>,
signType: signType,
privateKey: privateKey,
isShowLoading: isShowLoading,
);
}
/// 支付
Future<void> payOrderMap({
@required Map<String, dynamic> orderInfo,
String signType = SIGNTYPE_RSA2,
@required String privateKey,
bool isShowLoading = true,
}) {
assert(orderInfo?.isNotEmpty ?? false);
assert(privateKey?.isNotEmpty ?? false);
String charset = orderInfo['charset'] as String;
Encoding encoding =
(charset?.isNotEmpty ?? false) ? Encoding.getByName(charset) : null;
encoding ??= utf8;
Map<String, dynamic> clone = <String, dynamic>{
...orderInfo,
'sign_type': signType,
};
String param = _param(clone, encoding);
String sign = _sign(clone, signType, privateKey);
return payOrderSign(
orderInfo:
'$param&sign=${Uri.encodeQueryComponent(sign, encoding: encoding)}',
isShowLoading: isShowLoading,
);
}
/// 支付 - x.y.z-Android-Only 版本下 iOS 调用会直接抛出异常 No implementation [MissingPluginException]
Future<void> payOrderSign({
@required String orderInfo,
bool isShowLoading = true,
}) {
assert(orderInfo?.isNotEmpty ?? false);
return _channel.invokeMethod<void>(
_METHOD_PAY,
<String, dynamic>{
_ARGUMENT_KEY_ORDERINFO: orderInfo,
_ARGUMENT_KEY_ISSHOWLOADING: isShowLoading,
},
);
}
/// 登录
Future<void> auth({
@required String appId, // 支付宝分配给开发者的应用ID
@required String pid, // 签约的支付宝账号对应的支付宝唯一用户号,以2088开头的16位纯数字组成
@required String targetId, // 商户标识该次用户授权请求的ID,该值在商户端应保持唯一
String authType =
AUTHTYPE_AUTHACCOUNT, // 标识授权类型,取值范围:AUTHACCOUNT 代表授权;LOGIN 代表登录
String signType =
SIGNTYPE_RSA2, // 商户生成签名字符串所使用的签名算法类型,目前支持 RSA2 和 RSA ,推荐使用 RSA2
@required String privateKey,
bool isShowLoading = true,
}) {
assert((appId?.isNotEmpty ?? false) && appId.length <= 16);
assert((pid?.isNotEmpty ?? false) && pid.length <= 16);
assert((targetId?.isNotEmpty ?? false) && targetId.length <= 32);
assert(authType == AUTHTYPE_AUTHACCOUNT || authType == AUTHTYPE_LOGIN);
assert(privateKey?.isNotEmpty ?? false);
Map<String, dynamic> authInfo = <String, dynamic>{
'apiname': 'com.alipay.account.auth',
'method': 'alipay.open.auth.sdk.code.get',
'app_id': appId,
'app_name': 'mc',
'biz_type': 'openservice',
'pid': pid,
'product_id': 'APP_FAST_LOGIN',
'scope': 'kuaijie',
'target_id': targetId,
'auth_type': authType,
};
authInfo['sign_type'] = signType;
Encoding encoding = utf8; // utf-8
String param = _param(authInfo, encoding);
String sign = _sign(authInfo, signType, privateKey);
return authSign(
info: '$param&sign=${Uri.encodeQueryComponent(sign, encoding: encoding)}',
isShowLoading: isShowLoading,
);
}
/// 登录 - x.y.z-Android-Only 版本下 iOS 调用会直接抛出异常 No implementation [MissingPluginException]
Future<void> authSign({
@required String info,
bool isShowLoading = true,
}) {
assert(info != null && info.isNotEmpty);
return _channel.invokeMethod<void>(
_METHOD_AUTH,
<String, dynamic>{
_ARGUMENT_KEY_AUTHINFO: info,
_ARGUMENT_KEY_ISSHOWLOADING: isShowLoading,
},
);
}
String _param(Map<String, dynamic> map, Encoding encoding) {
return map.entries
.map((MapEntry<String, dynamic> e) =>
'${e.key}=${Uri.encodeQueryComponent('${e.value}', encoding: encoding)}')
.join('&');
}
String _sign(Map<String, dynamic> map, String signType, String privateKey) {
// 参数排序
List<String> keys = map.keys.toList();
keys.sort();
String content = keys.map((String e) => '$e=${map[e]}').join('&');
String sign;
switch (signType) {
case SIGNTYPE_RSA:
sign = base64
.encode(RsaSigner.sha1Rsa(privateKey).sign(utf8.encode(content)));
break;
case SIGNTYPE_RSA2:
sign = base64
.encode(RsaSigner.sha256Rsa(privateKey).sign(utf8.encode(content)));
break;
default:
throw UnsupportedError('Alipay sign_type($signType) is not supported!');
}
return sign;
}
}
import 'dart:convert';
import 'dart:typed_data';
import 'package:asn1lib/asn1lib.dart';
import 'package:pointycastle/pointycastle.dart';
import 'package:pointycastle/signers/rsa_signer.dart';
class RsaKeyParser {
RSAPublicKey parsePublic(String key) {
List<String> rows = key.split('\n');
String header = rows.first;
if (header == '-----BEGIN RSA PUBLIC KEY-----') {
return _parsePublic(_parseSequence(rows));
}
if (header == '-----BEGIN PUBLIC KEY-----') {
return _parsePublic(_pkcs8PublicSequence(_parseSequence(rows)));
}
throw UnsupportedError('PEMKey($key) is unsupported');
}
RSAPrivateKey parsePrivate(String key) {
List<String> rows = key.split('\n');
String header = rows.first;
if (header == '-----BEGIN RSA PRIVATE KEY-----') {
return _parsePrivate(_parseSequence(rows));
}
if (header == '-----BEGIN PRIVATE KEY-----') {
return _parsePrivate(_pkcs8PrivateSequence(_parseSequence(rows)));
}
throw UnsupportedError('PEMKey($key) is unsupported');
}
RSAPublicKey _parsePublic(ASN1Sequence sequence) {
BigInt modulus = (sequence.elements[0] as ASN1Integer).valueAsBigInteger;
BigInt exponent = (sequence.elements[1] as ASN1Integer).valueAsBigInteger;
return RSAPublicKey(modulus, exponent);
}
RSAPrivateKey _parsePrivate(ASN1Sequence sequence) {
BigInt modulus = (sequence.elements[1] as ASN1Integer).valueAsBigInteger;
BigInt exponent = (sequence.elements[3] as ASN1Integer).valueAsBigInteger;
BigInt p = (sequence.elements[4] as ASN1Integer).valueAsBigInteger;
BigInt q = (sequence.elements[5] as ASN1Integer).valueAsBigInteger;
return RSAPrivateKey(modulus, exponent, p, q);
}
ASN1Sequence _parseSequence(List<String> rows) {
String keyText = rows
.skipWhile((String row) => row.startsWith('-----BEGIN'))
.takeWhile((String row) => !row.startsWith('-----END'))
.map((String row) => row.trim())
.join('');
Uint8List keyBytes = Uint8List.fromList(base64.decode(keyText));
ASN1Parser asn1Parser = ASN1Parser(keyBytes);
return asn1Parser.nextObject() as ASN1Sequence;
}
ASN1Sequence _pkcs8PublicSequence(ASN1Sequence sequence) {
ASN1Object object = sequence.elements[1];
List<int> bytes = object.valueBytes().sublist(1);
ASN1Parser parser = ASN1Parser(Uint8List.fromList(bytes));
return parser.nextObject() as ASN1Sequence;
}
ASN1Sequence _pkcs8PrivateSequence(ASN1Sequence sequence) {
ASN1Object object = sequence.elements[2];
Uint8List bytes = object.valueBytes();
ASN1Parser parser = ASN1Parser(bytes);
return parser.nextObject() as ASN1Sequence;
}
}
class RsaSigner {
RsaSigner(RSASigner rsaSigner, RSAPrivateKey privateKey)
: _rsaSigner = rsaSigner,
_privateKey = privateKey;
final RSASigner _rsaSigner;
final RSAPrivateKey _privateKey;
List<int> sign(List<int> message) {
_rsaSigner
..reset()
..init(true, PrivateKeyParameter<RSAPrivateKey>(_privateKey));
RSASignature signature =
_rsaSigner.generateSignature(Uint8List.fromList(message));
return signature.bytes;
}
static RsaSigner sha1Rsa(String privateKey) {
return RsaSigner(Signer('SHA-1/RSA') as RSASigner,
RsaKeyParser().parsePrivate(privateKey));
}
static RsaSigner sha256Rsa(String privateKey) {
return RsaSigner(Signer('SHA-256/RSA') as RSASigner,
RsaKeyParser().parsePrivate(privateKey));
}
}
class RsaVerifier {
RsaVerifier(RSASigner rsaSigner, RSAPublicKey publicKey)
: _rsaSigner = rsaSigner,
_publicKey = publicKey;
final RSASigner _rsaSigner;
final RSAPublicKey _publicKey;
bool verify(List<int> message, List<int> signature) {
_rsaSigner
..reset()
..init(false, PublicKeyParameter<RSAPublicKey>(_publicKey));
return _rsaSigner.verifySignature(Uint8List.fromList(message),
RSASignature(Uint8List.fromList(signature)));
}
static RsaVerifier sha1Rsa(String publicKey) {
return RsaVerifier(Signer('SHA-1/RSA') as RSASigner,
RsaKeyParser().parsePublic(publicKey));
}
static RsaVerifier sha256Rsa(String publicKey) {
return RsaVerifier(Signer('SHA-256/RSA') as RSASigner,
RsaKeyParser().parsePublic(publicKey));
}
}
int intFromString(String json) {
return (json?.isNotEmpty ?? false) ? int.parse(json) : null;
}
String intToString(int object) {
return object?.toString();
}
bool boolFromString(String json) {
return json != null ? json == true.toString() : null;
}
String boolToString(bool object) {
return object?.toString();
}
import 'package:alipay_kit/src/json/string_converter.dart';
import 'package:json_annotation/json_annotation.dart';
part 'alipay_auth_result.g.dart';
@JsonSerializable(
explicitToJson: true,
fieldRename: FieldRename.snake,
)
class AlipayAuthResult {
AlipayAuthResult({
this.success,
this.resultCode,
this.authCode,
this.userId,
});
factory AlipayAuthResult.fromJson(Map<String, dynamic> json) =>
_$AlipayAuthResultFromJson(json);
@JsonKey(
fromJson: boolFromString,
toJson: boolToString,
)
final bool success;
/// 200 业务处理成功,会返回authCode
/// 1005 账户已冻结,如有疑问,请联系支付宝技术支持
/// 202 系统异常,请稍后再试或联系支付宝技术支持
@JsonKey(
fromJson: intFromString,
toJson: intToString,
)
final int resultCode;
final String authCode;
final String userId;
Map<String, dynamic> toJson() => _$AlipayAuthResultToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'alipay_auth_result.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AlipayAuthResult _$AlipayAuthResultFromJson(Map<String, dynamic> json) {
return AlipayAuthResult(
success: boolFromString(json['success'] as String),
resultCode: intFromString(json['result_code'] as String),
authCode: json['auth_code'] as String,
userId: json['user_id'] as String,
);
}
Map<String, dynamic> _$AlipayAuthResultToJson(AlipayAuthResult instance) =>
<String, dynamic>{
'success': boolToString(instance.success),
'result_code': intToString(instance.resultCode),
'auth_code': instance.authCode,
'user_id': instance.userId,
};
import 'package:alipay_kit/src/json/string_converter.dart';
import 'package:alipay_kit/src/model/alipay_auth_result.dart';
import 'package:json_annotation/json_annotation.dart';
part 'alipay_resp.g.dart';
@JsonSerializable(
explicitToJson: true,
)
class AlipayResp {
AlipayResp({
this.resultStatus,
this.result,
this.memo,
});
factory AlipayResp.fromJson(Map<String, dynamic> json) =>
_$AlipayRespFromJson(json);
/// 支付状态,参考支付宝的文档https://docs.open.alipay.com/204/105695/
/// 返回码,标识支付状态,含义如下:
/// 9000——订单支付成功 下面的result有值
/// 8000——正在处理中
/// 4000——订单支付失败
/// 5000——重复请求
/// 6001——用户中途取消
/// 6002——网络连接出错
@JsonKey(
fromJson: intFromString,
toJson: intToString,
)
final int resultStatus;
/// 支付后结果
final String result;
final String memo;
AlipayAuthResult parseAuthResult() {
if (resultStatus == 9000) {
if (result != null && result.isNotEmpty) {
Map<String, String> params =
Uri.parse('alipay://alipay?$result').queryParameters;
return AlipayAuthResult.fromJson(params);
}
}
return null;
}
Map<String, dynamic> toJson() => _$AlipayRespToJson(this);
}
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'alipay_resp.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
AlipayResp _$AlipayRespFromJson(Map<String, dynamic> json) {
return AlipayResp(
resultStatus: intFromString(json['resultStatus'] as String),
result: json['result'] as String,
memo: json['memo'] as String,
);
}
Map<String, dynamic> _$AlipayRespToJson(AlipayResp instance) =>
<String, dynamic>{
'resultStatus': intToString(instance.resultStatus),
'result': instance.result,
'memo': instance.memo,
};
# Generated by pub
# See https://dart.dev/tools/pub/glossary#lockfile
packages:
asn1lib:
dependency: "direct main"
description:
name: asn1lib
url: "https://pub.flutter-io.cn"
source: hosted
version: "0.5.15"
characters:
dependency: transitive
description:
name: characters
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.1.0"
collection:
dependency: transitive
description:
name: collection
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.15.0"
flutter:
dependency: "direct main"
description: flutter
source: sdk
version: "0.0.0"
json_annotation:
dependency: "direct main"
description:
name: json_annotation
url: "https://pub.flutter-io.cn"
source: hosted
version: "3.1.1"
meta:
dependency: transitive
description:
name: meta
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.7.0"
pointycastle:
dependency: "direct main"
description:
name: pointycastle
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.0.2"
sky_engine:
dependency: transitive
description: flutter
source: sdk
version: "0.0.99"
typed_data:
dependency: transitive
description:
name: typed_data
url: "https://pub.flutter-io.cn"
source: hosted
version: "1.3.0"
vector_math:
dependency: transitive
description:
name: vector_math
url: "https://pub.flutter-io.cn"
source: hosted
version: "2.1.0"
sdks:
dart: ">=2.12.0 <3.0.0"
flutter: ">=1.10.0"
name: alipay_kit
description: A powerful Flutter plugin allowing developers to auth/pay with natvie Android & iOS Alipay SDKs.
version: 2.0.0
homepage: https://github.com/v7lin/fake_alipay
environment:
sdk: ">=2.7.0 <3.0.0"
flutter: ">=1.10.0"
dependencies:
asn1lib: ^0.5.8
pointycastle: ^1.0.0
flutter:
sdk: flutter
json_annotation: '>=2.0.0 <4.0.0'
# The following section is specific to Flutter.
flutter:
plugin:
platforms:
android:
package: io.github.v7lin.alipay_kit
pluginClass: AlipayKitPlugin
ios:
pluginClass: AlipayKitPlugin
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment