Browse Source

优化性能

dongdayu 5 years ago
parent
commit
41ad5c3e6c

+ 3
- 0
.gitignore View File

@@ -42,3 +42,6 @@ local.properties
42 42
 buck-out/
43 43
 \.buckd/
44 44
 *.keystore
45
+
46
+# vscode
47
+.vscode/

+ 79
- 81
README.md View File

@@ -22,33 +22,15 @@ npm i @yyyyu/react-native-geetest-sensebot --save
22 22
 react-native link @yyyyu/react-native-geetest-sensebot
23 23
 ```
24 24
 
25
-### iOS 如果没有使用 CocoaPods
25
+### iOS 使用 CocoaPods
26 26
 
27 27
 在 Linked Frameworks and Libraries 中添加 node_modules/@yyyyu/react-native-geetest-sensebot/ios/SDK/GT3Captcha.framework
28 28
 
29 29
 ![add framework](doc/images/ios-add-framework.png)
30 30
 
31
-如果编译报错 <span style="color:red;font-weight:bold;">Framework not found GT3Captcha</span>, 在 Framework Search Paths 添加 $(SRCROOT)/../node_modules/@yyyyu/react-native-geetest-sensebot/ios/SDK
32
-
33
-![add framework search path](doc/images/ios-add-framework-search-paths.png)
34
-
35 31
 ### Android
36 32
 
37
-1. android/build.gradle
38
-
39
-```Groovy
40
-allprojects {
41
-    repositories {
42
-        // ...
43
-        // 与 android/app/build.gradle 中名称一致
44
-        flatDir {
45
-            dirs project(':@yyyyu_react-native-geetest-sensebot').file('libs')
46
-        }
47
-    }
48
-}
49
-```
50
-
51
-2. AndroidManifest.xml 中添加权限
33
+在 AndroidManifest.xml 文件中添加权限
52 34
 
53 35
 ```xml
54 36
 // ...
@@ -63,7 +45,7 @@ allprojects {
63 45
 ```javascript
64 46
 import React, { Component } from 'react'
65 47
 import { View, Button } from 'react-native'
66
-import RNGeetestSensebot from '@yyyyu/react-native-geetest-sensebot'
48
+import * as RNGeetestSensebot from '@yyyyu/react-native-geetest-sensebot'
67 49
 
68 50
 export default class App extends Component {
69 51
   geetest = async () => {
@@ -95,10 +77,10 @@ export default class App extends Component {
95 77
         backgroundBlurEffectIOS: RNGeetestSensebot.BackgroundBlurEffectIOS.Regular,
96 78
         // optional
97 79
         onEvent: (code, data) => {
98
-          if (code === RNGeetestSensebot.Event.FAILED) {
80
+          if (code === RNGeetestSensebot.Events.FAILED) {
99 81
             console.log('Validate failed, reason: %s', data[0])
100 82
           } else {
101
-            console.log(RNGeetestSensebot.Event[code], data)
83
+            console.log(RNGeetestSensebot.Events[code], data)
102 84
           }
103 85
         }
104 86
       })
@@ -134,69 +116,85 @@ export default class App extends Component {
134 116
 ## Option
135 117
 
136 118
 ```javascript
137
-interface Option {
138
-  // API1
139
-  api1Result: API1Result;
140
-  // debug
141
-  debug?: boolean;
142
-  // view 加载超时时间,默认10000
143
-  loadTimeout?: number;
144
-  // 第二步向极验服务器发送请求超时时间,默认10000
145
-  reqTimeout?: number;
146
-  // 语言,如果为null则使用系统默认语言
147
-  lang?: Lang;
148
-  // 点击背景是否可以取消验证
149
-  enableBackgroundCancel?: boolean;
150
-  // 背景色 IOS Only
151
-  backgroundColorIOS?: any;
152
-  // 背景模糊类型 IOS Only
153
-  backgroundBlurEffectIOS?: BackgroundBlurEffectIOS;
154
-  // 事件监听
155
-  onEvent?: (code: Event, data?: Array<number | string>) => void;
119
+export interface IOption {
120
+    // API1
121
+    api1Result: IAPI1Result;
122
+    // debug
123
+    debug?: boolean;
124
+    // view 加载超时时间,默认10000
125
+    loadTimeout?: number;
126
+    // 第二步向极验服务器发送请求超时时间,默认10000
127
+    reqTimeout?: number;
128
+    // 语言,如果为null则使用系统默认语言
129
+    lang?: Lang;
130
+    // 点击背景是否可以取消验证
131
+    enableBackgroundCancel?: boolean;
132
+    // 背景色 IOS Only
133
+    backgroundColorIOS?: any;
134
+    // 背景模糊类型 IOS Only
135
+    backgroundBlurEffectIOS?: BackgroundBlurEffectIOS;
136
+    // 事件监听
137
+    onEvent?: (code: Events, data?: Array<number | string>) => void;
156 138
 }
157
-interface API1Result {
158
-  success: 0 | 1;
159
-  challenge: string;
160
-  gt: string;
161
-  new_captcha: boolean;
139
+
140
+export interface IAPI1Result {
141
+    success: 0 | 1;
142
+    challenge: string;
143
+    gt: string;
144
+    new_captcha: boolean;
145
+    [key: string]: any;
162 146
 }
163
-enum Lang {
164
-  System = "system",
165
-  ZH = "zh",
166
-  ZH_TW = "zh-tw",
167
-  ZH_HK = "zh-hk",
168
-  EN = "en",
169
-  ID = "id",
170
-  JA = "ja",
171
-  KO = "ko",
172
-  RU = "ru",
173
-  AR = "ar",
174
-  ES = "es",
175
-  PT_PT = "pt-pt",
176
-  FR = "fr",
177
-  DE = "de"
147
+
148
+export enum Lang {
149
+    System = "system", // 跟随系统
150
+    ZH = "zh", // 简体中文
151
+    ZH_TW = "zh-tw", // 繁体中文
152
+    ZH_HK = "zh-hk", // 繁体中文
153
+    EN = "en", // 英语
154
+    ID = "id", // 印尼语
155
+    JA = "ja", // 日语
156
+    KO = "ko", // 韩语
157
+    RU = "ru", // 俄语
158
+    AR = "ar", // 阿拉伯语
159
+    ES = "es", // 西班牙语
160
+    PT_PT = "pt-pt", // 葡萄牙语
161
+    FR = "fr", // 法语
162
+    DE = "de", // 德语
178 163
 }
179
-enum BackgroundBlurEffectIOS {
180
-  None = -1,
181
-  ExtraLight = 0,
182
-  Light = 1,
183
-  Dark = 2,
184
-  Regular = 3,
185
-  Prominent = 4
164
+
165
+export enum BackgroundBlurEffectIOS {
166
+    None = -1,
167
+    ExtraLight = 0,
168
+    Light,
169
+    Dark,
170
+    Regular, // NS_ENUM_AVAILABLE_IOS(10_0)
171
+    Prominent, // NS_ENUM_AVAILABLE_IOS(10_0)
186 172
 }
187
-enum Event {
188
-  RESULT = 1,
189
-  CLOSED = 2,
190
-  FAILED = 3,
191
-  ERROR = 0
173
+
174
+export enum Events {
175
+    // 验证结果
176
+    RESULT = 1,
177
+    // 验证窗口关闭
178
+    CLOSED = 2,
179
+    // 验证失败
180
+    FAILED = 3,
181
+    // 发生错误
182
+    ERROR = 0,
192 183
 }
193
-enum Error {
194
-  PARAMETER_PARSE_FAILED = -1,
195
-  ANDROID_ACTIVITY_DESTROYED = -2
184
+
185
+export enum Errors {
186
+    // 参数解析错误
187
+    PARAMETER_PARSE_FAILED = -1,
188
+    // 安卓 activity 已经销毁
189
+    ANDROID_ACTIVITY_DESTROYED = -2,
190
+    // 重复启动
191
+    DUPLICATE_START = -3,
196 192
 }
197
-interface Result {
198
-  geetest_challenge: string;
199
-  geetest_seccode: string;
200
-  geetest_validate: string;
193
+
194
+export interface IResult {
195
+    geetest_challenge: string;
196
+    geetest_seccode: string;
197
+    geetest_validate: string;
198
+    [key: string]: any;
201 199
 }
202 200
 ```

+ 8
- 10
RNLGeetestSensebot.podspec View File

@@ -1,22 +1,20 @@
1 1
 require 'json'
2 2
 
3
-package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
3
+package_json = JSON.parse(File.read(File.join(__dir__, 'package.json')))
4 4
 
5 5
 Pod::Spec.new do |s|
6 6
   s.name                = 'RNLGeetestSensebot'
7
-  s.version             = package['version']
8
-  s.summary             = package['description']
9
-  s.description         = package['description']
10
-  s.license             = package['license']
11
-  s.author              = { package['author'] => 'g592842897@gmail.com' }
12
-  s.homepage            = package['homepage']
13
-  s.source              = { :git => package['repository']['url'], :tag => package['version'] }
7
+  s.version             = package_json["version"]
8
+  s.author              = { package_json['author']['name'] => package_json['author']['email'] }
9
+  s.license             = { :type => package_json['license'] }
10
+  s.homepage            = package_json['homepage']
11
+  s.source              = { :git => package_json['repository']['url'], :tag => "v#{package_json['version']}" }
12
+  s.summary             = package_json['description']
14 13
 
15
-  s.requires_arc        = true
16 14
   s.platform            = :ios, '8.0'
17 15
   s.source_files        = 'ios/RNLGeetestSensebot.{h,m}'
18 16
   s.vendored_frameworks = 'ios/SDK/GT3Captcha.framework'
19 17
   s.resource            = 'ios/SDK/GT3Captcha.bundle'
20 18
   s.framework           = 'JavaScriptCore', 'WebKit'
21
-  s.pod_target_xcconfig = { 'HEADER_SEARCH_PATHS' => '$(BUILT_PRODUCTS_DIR)/../include' }
19
+  s.dependency 'React'
22 20
 end

+ 9
- 27
android/build.gradle View File

@@ -1,42 +1,24 @@
1
-def safeExtGet(prop, fallback) {
2
-    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
3
-}
4
-
5
-buildscript {
6
-    repositories {
7
-        jcenter()
8
-    }
9
-
10
-    dependencies {
11
-        classpath 'com.android.tools.build:gradle:1.3.1'
12
-    }
13
-}
14
-
15 1
 apply plugin: 'com.android.library'
16 2
 
17 3
 android {
18
-    compileSdkVersion safeExtGet('compileSdkVersion', 28)
19
-    buildToolsVersion safeExtGet('buildToolsVersion', "28.0.3")
20
-
21 4
     defaultConfig {
22 5
         minSdkVersion safeExtGet('minSdkVersion', 16)
23 6
         targetSdkVersion safeExtGet('targetSdkVersion', 28)
24
-        versionCode 1
25
-        versionName "1.0"
26 7
     }
8
+
9
+    compileSdkVersion safeExtGet('compileSdkVersion', 28)
10
+    buildToolsVersion safeExtGet('buildToolsVersion', "28.0.3")
11
+
27 12
     lintOptions {
28 13
         abortOnError false
29 14
     }
30 15
 }
31 16
 
32
-repositories {
33
-    mavenCentral()
34
-    flatDir {
35
-        dirs 'libs'
36
-    }
37
-}
38
-
39 17
 dependencies {
40 18
     implementation 'com.facebook.react:react-native:+'
41
-    implementation(name: 'geetest_sensebot_android_v4.0.7_20190311', ext: 'aar')
19
+    implementation files('libs/geetest_sensebot_android_v4.0.7_20190311.aar')
20
+}
21
+
22
+def safeExtGet(prop, fallback) {
23
+    rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
42 24
 }

+ 86
- 74
android/src/main/java/com/rnlib/geetestsensebot/RNLGeetestSensebotModule.java View File

@@ -3,6 +3,7 @@ package com.rnlib.geetestsensebot;
3 3
 import android.app.Activity;
4 4
 
5 5
 import com.facebook.react.bridge.Arguments;
6
+import com.facebook.react.bridge.Callback;
6 7
 import com.facebook.react.bridge.LifecycleEventListener;
7 8
 import com.facebook.react.bridge.ReactApplicationContext;
8 9
 import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -22,48 +23,49 @@ import org.json.JSONObject;
22 23
 import javax.annotation.Nonnull;
23 24
 import javax.annotation.Nullable;
24 25
 
25
-public class RNLGeetestSensebotModule extends ReactContextBaseJavaModule {
26
-    private static final String NAME = "RNLGeetestSensebot";
27
-    private static final String EVENT_NAME = "RNLGeetestSensebotEvent";
26
+public class RNLGeetestSensebotModule extends ReactContextBaseJavaModule implements LifecycleEventListener {
27
+    private static final String ModuleName = "RNLGeetestSensebot";
28
+    private static final String EventName = "RNLGeetestSensebotEvent";
28 29
 
29 30
     private final ReactApplicationContext mReactContext;
30 31
     private GT3GeetestUtils mGT3GeetestUtils;
32
+    private GT3ConfigBean mGT3ConfigBean;
31 33
 
32 34
     RNLGeetestSensebotModule(ReactApplicationContext reactContext) {
33 35
         super(reactContext);
34 36
         mReactContext = reactContext;
37
+        mReactContext.addLifecycleEventListener(this);
35 38
     }
36 39
 
37 40
     @Nonnull
38 41
     @Override
39 42
     public String getName() {
40
-        return NAME;
43
+        return ModuleName;
41 44
     }
42 45
 
43 46
     @ReactMethod
44 47
     public void start(final ReadableMap option) {
45
-        GT3ConfigBean mGT3ConfigBean = new GT3ConfigBean();
46
-        mGT3ConfigBean.setPattern(1); // 1 -> bind 自定义按钮
48
+        GT3ConfigBean gt3ConfigBean = getSharedGT3ConfigBean();
47 49
         try {
48 50
             // debug
49 51
             boolean debug = option.getBoolean("debug");
50
-            mGT3ConfigBean.setDebug(debug);
52
+            gt3ConfigBean.setDebug(debug);
51 53
             // view load timeout
52 54
             int timeout = option.getInt("loadTimeout");
53
-            mGT3ConfigBean.setTimeout(timeout);
55
+            gt3ConfigBean.setTimeout(timeout);
54 56
             // request timeout
55 57
             int webviewTimeout = option.getInt("reqTimeout");
56
-            mGT3ConfigBean.setWebviewTimeout(webviewTimeout);
58
+            gt3ConfigBean.setWebviewTimeout(webviewTimeout);
57 59
             // lang
58 60
             String lang = option.getString("lang");
59 61
             if (lang != null && !lang.equals("system")) {
60
-                mGT3ConfigBean.setLang(lang);
62
+                gt3ConfigBean.setLang(lang);
61 63
             }
62 64
             // enable background cancel
63 65
             boolean canceledOnTouchOutside = option.getBoolean("enableBackgroundCancel");
64
-            mGT3ConfigBean.setCanceledOnTouchOutside(canceledOnTouchOutside);
66
+            gt3ConfigBean.setCanceledOnTouchOutside(canceledOnTouchOutside);
65 67
             // api1 json result
66
-            mGT3ConfigBean.setApi1Json(new JSONObject(
68
+            gt3ConfigBean.setApi1Json(new JSONObject(
67 69
                     option.getString("api1Result")));
68 70
         } catch (Exception e) {
69 71
             sendEvent(Event.Error.getCode(),
@@ -71,93 +73,103 @@ public class RNLGeetestSensebotModule extends ReactContextBaseJavaModule {
71 73
             return;
72 74
         }
73 75
 
74
-        mGT3ConfigBean.setListener(new GT3Listener() {
75
-            @Override
76
-            public void onDialogResult(String s) {
77
-                super.onDialogResult(s);
78
-                sendEvent(Event.Result.getCode(), s);
79
-            }
76
+        Activity activity = mReactContext.getCurrentActivity();
77
+        if (activity == null) {
78
+            sendEvent(Event.Error.getCode(),
79
+                    Error.AndroidActivityDestroyed.getCode(), "Activity has been destroyed.");
80
+            return;
81
+        }
82
+        mGT3GeetestUtils = new GT3GeetestUtils(activity);
83
+        mGT3GeetestUtils.init(gt3ConfigBean);
80 84
 
85
+        UiThreadUtil.runOnUiThread(new Runnable() {
81 86
             @Override
82
-            public void onClosed(int i) {
83
-                sendEvent(Event.Closed.getCode());
87
+            public void run() {
88
+                mGT3GeetestUtils.startCustomFlow();
89
+                mGT3GeetestUtils.getGeetest();
84 90
             }
91
+        });
92
+    }
85 93
 
94
+    @ReactMethod
95
+    public void stop(final Callback callback) {
96
+        UiThreadUtil.runOnUiThread(new Runnable() {
86 97
             @Override
87
-            public void onFailed(GT3ErrorBean gt3ErrorBean) {
88
-                WritableMap result = Arguments.createMap();
89
-                result.putString("errorCode", gt3ErrorBean.errorCode);
90
-                result.putString("errorDesc", gt3ErrorBean.errorDesc);
91
-                result.putDouble("duration", gt3ErrorBean.duration);
92
-                result.putString("challenge", gt3ErrorBean.challenge);
93
-                result.putString("type", gt3ErrorBean.type);
94
-                result.putString("sdkVersion", gt3ErrorBean.sdkVersion);
95
-                JSONObject json = new JSONObject(result.toHashMap());
96
-                sendEvent(Event.Failed.getCode(), json.toString());
98
+            public void run() {
99
+                mGT3GeetestUtils.destory();
100
+                callback.invoke();
97 101
             }
102
+        });
103
+        mReactContext.removeLifecycleEventListener(this);
104
+    }
98 105
 
99
-            @Override
100
-            public void onButtonClick() {
106
+    private GT3ConfigBean getSharedGT3ConfigBean() {
107
+        if (mGT3ConfigBean == null) {
108
+            mGT3ConfigBean = new GT3ConfigBean();
109
+            mGT3ConfigBean.setPattern(1); // 1 -> bind 自定义按钮
101 110
 
102
-            }
111
+            mGT3ConfigBean.setListener(new GT3Listener() {
112
+                @Override
113
+                public void onDialogResult(String s) {
114
+                    super.onDialogResult(s);
115
+                    sendEvent(Event.Result.getCode(), s);
116
+                }
103 117
 
104
-            @Override
105
-            public void onSuccess(String s) {
118
+                @Override
119
+                public void onClosed(int i) {
120
+                    sendEvent(Event.Closed.getCode());
121
+                }
106 122
 
107
-            }
123
+                @Override
124
+                public void onFailed(GT3ErrorBean gt3ErrorBean) {
125
+                    WritableMap result = Arguments.createMap();
126
+                    result.putString("errorCode", gt3ErrorBean.errorCode);
127
+                    result.putString("errorDesc", gt3ErrorBean.errorDesc);
128
+                    result.putDouble("duration", gt3ErrorBean.duration);
129
+                    result.putString("challenge", gt3ErrorBean.challenge);
130
+                    result.putString("type", gt3ErrorBean.type);
131
+                    result.putString("sdkVersion", gt3ErrorBean.sdkVersion);
132
+                    JSONObject json = new JSONObject(result.toHashMap());
133
+                    sendEvent(Event.Failed.getCode(), json.toString());
134
+                }
108 135
 
109
-            @Override
110
-            public void onStatistics(String s) {
136
+                @Override
137
+                public void onButtonClick() {
111 138
 
112
-            }
113
-        });
139
+                }
114 140
 
115
-        Activity activity = mReactContext.getCurrentActivity();
116
-        if (activity == null) {
117
-            sendEvent(Event.Error.getCode(),
118
-                    Error.AndroidActivityDestroyed.getCode(), "Activity has been destroyed.");
119
-            return;
141
+                @Override
142
+                public void onSuccess(String s) {
143
+
144
+                }
145
+
146
+                @Override
147
+                public void onStatistics(String s) {
148
+
149
+                }
150
+            });
120 151
         }
121
-        mGT3GeetestUtils = new GT3GeetestUtils(activity);
122
-        mGT3GeetestUtils.init(mGT3ConfigBean);
123
-        mReactContext.addLifecycleEventListener(new LifecycleEventListener() {
124
-            @Override
125
-            public void onHostResume() {
152
+        return mGT3ConfigBean;
153
+    }
126 154
 
127
-            }
155
+    @Override
156
+    public void onHostResume() {
128 157
 
129
-            @Override
130
-            public void onHostPause() {
158
+    }
131 159
 
132
-            }
160
+    @Override
161
+    public void onHostPause() {
133 162
 
134
-            @Override
135
-            public void onHostDestroy() {
136
-                if (mGT3GeetestUtils != null) {
137
-                    mGT3GeetestUtils.destory();
138
-                }
139
-            }
140
-        });
141
-        UiThreadUtil.runOnUiThread(new Runnable() {
142
-            @Override
143
-            public void run() {
144
-                if (mGT3GeetestUtils != null) {
145
-                    mGT3GeetestUtils.startCustomFlow();
146
-                    mGT3GeetestUtils.getGeetest();
147
-                }
148
-            }
149
-        });
150 163
     }
151 164
 
152
-    @ReactMethod
153
-    public void stop() {
165
+    @Override
166
+    public void onHostDestroy() {
154 167
         if (mGT3GeetestUtils != null) {
155 168
             UiThreadUtil.runOnUiThread(new Runnable() {
156 169
                 @Override
157 170
                 public void run() {
158 171
                     if (mGT3GeetestUtils != null) {
159 172
                         mGT3GeetestUtils.destory();
160
-                        mGT3GeetestUtils = null;
161 173
                     }
162 174
                 }
163 175
             });
@@ -188,7 +200,7 @@ public class RNLGeetestSensebotModule extends ReactContextBaseJavaModule {
188 200
         }
189 201
         mReactContext
190 202
                 .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
191
-                .emit(EVENT_NAME, event);
203
+                .emit(EventName, event);
192 204
     }
193 205
 
194 206
     private enum Event {

+ 42
- 62
dist/index.d.ts View File

@@ -1,63 +1,43 @@
1
-declare namespace GeetestSensebot {
2
-    enum Lang {
3
-        System = "system",
4
-        ZH = "zh",
5
-        ZH_TW = "zh-tw",
6
-        ZH_HK = "zh-hk",
7
-        EN = "en",
8
-        ID = "id",
9
-        JA = "ja",
10
-        KO = "ko",
11
-        RU = "ru",
12
-        AR = "ar",
13
-        ES = "es",
14
-        PT_PT = "pt-pt",
15
-        FR = "fr",
16
-        DE = "de"
17
-    }
18
-    enum BackgroundBlurEffectIOS {
19
-        None = -1,
20
-        ExtraLight = 0,
21
-        Light = 1,
22
-        Dark = 2,
23
-        Regular = 3,
24
-        Prominent = 4
25
-    }
26
-    interface Option {
27
-        api1Result: API1Result;
28
-        debug?: boolean;
29
-        loadTimeout?: number;
30
-        reqTimeout?: number;
31
-        lang?: Lang;
32
-        enableBackgroundCancel?: boolean;
33
-        backgroundColorIOS?: any;
34
-        backgroundBlurEffectIOS?: BackgroundBlurEffectIOS;
35
-        onEvent?: (code: Event, data?: Array<number | string>) => void;
36
-    }
37
-    interface API1Result {
38
-        success: 0 | 1;
39
-        challenge: string;
40
-        gt: string;
41
-        new_captcha: boolean;
42
-        [key: string]: any;
43
-    }
44
-    interface Result {
45
-        geetest_challenge: string;
46
-        geetest_seccode: string;
47
-        geetest_validate: string;
48
-        [key: string]: any;
49
-    }
50
-    enum Event {
51
-        RESULT = 1,
52
-        CLOSED = 2,
53
-        FAILED = 3,
54
-        ERROR = 0
55
-    }
56
-    enum Error {
57
-        PARAMETER_PARSE_FAILED = -1,
58
-        ANDROID_ACTIVITY_DESTROYED = -2
59
-    }
60
-    function start(option: Option): Promise<Result>;
61
-    function stop(): void;
1
+import * as RNGSModule from "./module";
2
+export { BackgroundBlurEffectIOS, Lang } from "./module";
3
+export interface IAPI1Result {
4
+    success: 0 | 1;
5
+    challenge: string;
6
+    gt: string;
7
+    new_captcha: boolean;
8
+    [key: string]: any;
9
+}
10
+export interface IOption {
11
+    api1Result: IAPI1Result;
12
+    debug?: boolean;
13
+    loadTimeout?: number;
14
+    reqTimeout?: number;
15
+    lang?: RNGSModule.Lang;
16
+    enableBackgroundCancel?: boolean;
17
+    backgroundColorIOS?: any;
18
+    backgroundBlurEffectIOS?: RNGSModule.BackgroundBlurEffectIOS;
19
+    onEvent?: (code: Events, data?: Array<number | string>) => void;
20
+}
21
+export interface IResult {
22
+    geetest_challenge: string;
23
+    geetest_seccode: string;
24
+    geetest_validate: string;
25
+    [key: string]: any;
26
+}
27
+export declare enum Errors {
28
+    PARAMETER_PARSE_FAILED = -1,
29
+    ANDROID_ACTIVITY_DESTROYED = -2,
30
+    DUPLICATE_START = -3
31
+}
32
+export declare enum Events {
33
+    RESULT = 1,
34
+    CLOSED = 2,
35
+    FAILED = 3,
36
+    ERROR = 0
37
+}
38
+export declare function start(option: IOption): Promise<IResult>;
39
+export declare class GeetestError extends Error {
40
+    readonly code: number;
41
+    readonly message: string;
42
+    constructor(code: number, message: string);
62 43
 }
63
-export default GeetestSensebot;

+ 91
- 131
dist/index.js View File

@@ -1,137 +1,97 @@
1
-import { NativeModules, NativeEventEmitter, Platform, processColor } from 'react-native';
2
-const Exception = Error;
3
-var RNLGeetestSensebot;
4
-(function (RNLGeetestSensebot_1) {
5
-    // API
6
-    const RNLGeetestSensebot = NativeModules.RNLGeetestSensebot;
7
-    RNLGeetestSensebot_1.start = RNLGeetestSensebot.start;
8
-    RNLGeetestSensebot_1.stop = RNLGeetestSensebot.stop;
9
-    // Event
10
-    const EventName = 'RNLGeetestSensebotEvent';
11
-    const EventEmitter = new NativeEventEmitter(RNLGeetestSensebot);
12
-    RNLGeetestSensebot_1.addListener = (listener) => EventEmitter.addListener(EventName, listener);
13
-})(RNLGeetestSensebot || (RNLGeetestSensebot = {}));
14
-var GeetestSensebot;
15
-(function (GeetestSensebot) {
16
-    let Lang;
17
-    (function (Lang) {
18
-        Lang["System"] = "system";
19
-        Lang["ZH"] = "zh";
20
-        Lang["ZH_TW"] = "zh-tw";
21
-        Lang["ZH_HK"] = "zh-hk";
22
-        Lang["EN"] = "en";
23
-        Lang["ID"] = "id";
24
-        Lang["JA"] = "ja";
25
-        Lang["KO"] = "ko";
26
-        Lang["RU"] = "ru";
27
-        Lang["AR"] = "ar";
28
-        Lang["ES"] = "es";
29
-        Lang["PT_PT"] = "pt-pt";
30
-        Lang["FR"] = "fr";
31
-        Lang["DE"] = "de";
32
-    })(Lang = GeetestSensebot.Lang || (GeetestSensebot.Lang = {}));
33
-    let BackgroundBlurEffectIOS;
34
-    (function (BackgroundBlurEffectIOS) {
35
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["None"] = -1] = "None";
36
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["ExtraLight"] = 0] = "ExtraLight";
37
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Light"] = 1] = "Light";
38
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Dark"] = 2] = "Dark";
39
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Regular"] = 3] = "Regular";
40
-        BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Prominent"] = 4] = "Prominent";
41
-    })(BackgroundBlurEffectIOS = GeetestSensebot.BackgroundBlurEffectIOS || (GeetestSensebot.BackgroundBlurEffectIOS = {}));
42
-    let Event;
43
-    (function (Event) {
44
-        // 验证结果
45
-        Event[Event["RESULT"] = 1] = "RESULT";
46
-        // 验证窗口关闭
47
-        Event[Event["CLOSED"] = 2] = "CLOSED";
48
-        // 验证失败
49
-        Event[Event["FAILED"] = 3] = "FAILED";
50
-        // 发生错误
51
-        Event[Event["ERROR"] = 0] = "ERROR";
52
-    })(Event = GeetestSensebot.Event || (GeetestSensebot.Event = {}));
53
-    let Error;
54
-    (function (Error) {
55
-        // 参数解析错误
56
-        Error[Error["PARAMETER_PARSE_FAILED"] = -1] = "PARAMETER_PARSE_FAILED";
57
-        // 安卓 activity 已经销毁
58
-        Error[Error["ANDROID_ACTIVITY_DESTROYED"] = -2] = "ANDROID_ACTIVITY_DESTROYED";
59
-    })(Error = GeetestSensebot.Error || (GeetestSensebot.Error = {}));
60
-    const defaultOption = {
61
-        api1Result: '',
62
-        debug: false,
63
-        loadTimeout: 10000,
64
-        reqTimeout: 10000,
65
-        lang: Lang.System,
66
-        enableBackgroundCancel: false,
67
-        backgroundColorIOS: 0,
68
-        backgroundBlurEffectIOS: BackgroundBlurEffectIOS.None,
69
-    };
70
-    function parseConfig(c) {
71
-        const config = Object.assign({}, defaultOption);
72
-        config.api1Result = JSON.stringify(c.api1Result);
73
-        if (typeof c.debug === 'boolean') {
74
-            config.debug = c.debug;
1
+import * as RNGSModule from "./module";
2
+export { BackgroundBlurEffectIOS, Lang } from "./module";
3
+export var Errors;
4
+(function (Errors) {
5
+    // 参数解析错误
6
+    Errors[Errors["PARAMETER_PARSE_FAILED"] = -1] = "PARAMETER_PARSE_FAILED";
7
+    // 安卓 activity 已经销毁
8
+    Errors[Errors["ANDROID_ACTIVITY_DESTROYED"] = -2] = "ANDROID_ACTIVITY_DESTROYED";
9
+    // 重复运行
10
+    Errors[Errors["DUPLICATE_START"] = -3] = "DUPLICATE_START";
11
+})(Errors || (Errors = {}));
12
+export var Events;
13
+(function (Events) {
14
+    // 验证结果
15
+    Events[Events["RESULT"] = 1] = "RESULT";
16
+    // 验证窗口关闭
17
+    Events[Events["CLOSED"] = 2] = "CLOSED";
18
+    // 验证失败
19
+    Events[Events["FAILED"] = 3] = "FAILED";
20
+    // 发生错误
21
+    Events[Events["ERROR"] = 0] = "ERROR";
22
+})(Events || (Events = {}));
23
+var InternalStatus;
24
+(function (InternalStatus) {
25
+    InternalStatus[InternalStatus["None"] = 0] = "None";
26
+    // 认证中
27
+    InternalStatus[InternalStatus["Running"] = 1] = "Running";
28
+    // 停止认证中
29
+    InternalStatus[InternalStatus["Stoping"] = 0] = "Stoping";
30
+})(InternalStatus || (InternalStatus = {}));
31
+let internalStatus = InternalStatus.None;
32
+let eventListener = null;
33
+const DEFAULT_OPTION = {
34
+    api1Result: "",
35
+    debug: false,
36
+    loadTimeout: 10000,
37
+    reqTimeout: 10000,
38
+    lang: RNGSModule.Lang.System,
39
+    enableBackgroundCancel: false,
40
+    backgroundColorIOS: 0,
41
+    backgroundBlurEffectIOS: RNGSModule.BackgroundBlurEffectIOS.None,
42
+};
43
+// 进行行为认证
44
+export function start(option) {
45
+    return new Promise((resolve, reject) => {
46
+        if (internalStatus & InternalStatus.Running) {
47
+            return reject(new GeetestError(Errors.DUPLICATE_START, "Duplicate start"));
75 48
         }
76
-        if (typeof c.loadTimeout === 'number') {
77
-            config.loadTimeout = c.loadTimeout >> 0;
78
-        }
79
-        if (typeof c.reqTimeout === 'number') {
80
-            config.reqTimeout = c.reqTimeout >> 0;
81
-        }
82
-        if (typeof c.lang === 'string') {
83
-            config.lang = c.lang;
84
-        }
85
-        if (typeof c.enableBackgroundCancel === 'boolean') {
86
-            config.enableBackgroundCancel = c.enableBackgroundCancel;
87
-        }
88
-        if (c.backgroundColorIOS !== undefined) {
89
-            config.backgroundColorIOS = processColor(c.backgroundColorIOS);
90
-        }
91
-        if (typeof c.backgroundBlurEffectIOS === 'number') {
92
-            config.backgroundBlurEffectIOS = c.backgroundBlurEffectIOS;
93
-        }
94
-        return config;
95
-    }
96
-    let eventListener;
97
-    // 进行行为认证
98
-    function start(option) {
99
-        return new Promise((resolve, reject) => {
100
-            eventListener = RNLGeetestSensebot.addListener(([code, ...data]) => {
101
-                switch (code) {
102
-                    case Event.RESULT:
103
-                        stop();
104
-                        resolve(JSON.parse(data[0]));
105
-                        break;
106
-                    case Event.FAILED:
107
-                        // iOS 只要认证错误就会触发, android 多次认证错误最后自动关闭 view 时才会触发
108
-                        if (Platform.OS === 'android') {
109
-                            stop();
110
-                        }
111
-                        break;
112
-                    case Event.ERROR:
113
-                        stop();
114
-                        const error = new Exception(data[1]);
115
-                        Object.defineProperty(error, 'name', { value: 'RNGeetestError', writable: false });
116
-                        Object.defineProperty(error, 'code', { value: data[0], writable: false });
117
-                        reject(error);
118
-                        break;
119
-                }
120
-                if (typeof option.onEvent === 'function') {
121
-                    option.onEvent(code, data);
122
-                }
123
-            });
124
-            RNLGeetestSensebot.start(parseConfig(option));
49
+        internalStatus |= InternalStatus.Running;
50
+        eventListener = RNGSModule.addListener(([code, ...data]) => {
51
+            switch (code) {
52
+                case Events.RESULT:
53
+                    resolve(JSON.parse(data[0]));
54
+                    stop();
55
+                    break;
56
+                case Events.FAILED:
57
+                case Events.CLOSED:
58
+                    stop();
59
+                    break;
60
+                case Events.ERROR:
61
+                    reject(new GeetestError(data[0], data[1]));
62
+                    stop();
63
+                    break;
64
+            }
65
+            if (typeof option.onEvent === "function") {
66
+                option.onEvent(code, data);
67
+            }
125 68
         });
69
+        RNGSModule.start(RNGSModule.parseOption(option, DEFAULT_OPTION));
70
+    });
71
+}
72
+function stop() {
73
+    if (internalStatus & InternalStatus.Stoping) {
74
+        return;
126 75
     }
127
-    GeetestSensebot.start = start;
128
-    // 清理行为认证资源占用
129
-    function stop() {
130
-        if (eventListener && typeof eventListener.remove === 'function') {
76
+    internalStatus |= InternalStatus.Stoping;
77
+    RNGSModule.stop(() => {
78
+        internalStatus = InternalStatus.None;
79
+        if (eventListener && typeof eventListener.remove === "function") {
131 80
             eventListener.remove();
81
+            eventListener = null;
82
+        }
83
+    });
84
+}
85
+export class GeetestError extends Error {
86
+    constructor(code, message) {
87
+        super(message);
88
+        this.code = code;
89
+        this.message = message;
90
+        // @ts-ignore
91
+        if (Error.captureStackTrace) {
92
+            // @ts-ignore
93
+            Error.captureStackTrace(this, GeetestError);
132 94
         }
133
-        RNLGeetestSensebot.stop();
95
+        this.name = "GeetestError";
134 96
     }
135
-    GeetestSensebot.stop = stop;
136
-})(GeetestSensebot || (GeetestSensebot = {}));
137
-export default GeetestSensebot;
97
+}

+ 40
- 0
dist/module.d.ts View File

@@ -0,0 +1,40 @@
1
+export declare enum Lang {
2
+    System = "system",
3
+    ZH = "zh",
4
+    ZH_TW = "zh-tw",
5
+    ZH_HK = "zh-hk",
6
+    EN = "en",
7
+    ID = "id",
8
+    JA = "ja",
9
+    KO = "ko",
10
+    RU = "ru",
11
+    AR = "ar",
12
+    ES = "es",
13
+    PT_PT = "pt-pt",
14
+    FR = "fr",
15
+    DE = "de"
16
+}
17
+export declare enum BackgroundBlurEffectIOS {
18
+    None = -1,
19
+    ExtraLight = 0,
20
+    Light = 1,
21
+    Dark = 2,
22
+    Regular = 3,
23
+    Prominent = 4
24
+}
25
+declare type Callback = (_: any) => void;
26
+export declare const start: (option: IGSOption) => void;
27
+export declare const stop: (callback: Callback) => void;
28
+export declare const addListener: (listener: Callback) => import("react-native").EmitterSubscription;
29
+interface IGSOption {
30
+    api1Result: string;
31
+    debug: boolean;
32
+    loadTimeout: number;
33
+    reqTimeout: number;
34
+    lang: Lang;
35
+    enableBackgroundCancel: boolean;
36
+    backgroundColorIOS: number;
37
+    backgroundBlurEffectIOS: BackgroundBlurEffectIOS;
38
+}
39
+export declare function parseOption(o: any, defaultOption: IGSOption): IGSOption;
40
+export {};

+ 59
- 0
dist/module.js View File

@@ -0,0 +1,59 @@
1
+import { NativeEventEmitter, NativeModules, processColor } from "react-native";
2
+const RNGSModule = NativeModules.RNLGeetestSensebot;
3
+const RNGSEventEmitter = new NativeEventEmitter(RNGSModule);
4
+const EventName = "RNLGeetestSensebotEvent";
5
+export var Lang;
6
+(function (Lang) {
7
+    Lang["System"] = "system";
8
+    Lang["ZH"] = "zh";
9
+    Lang["ZH_TW"] = "zh-tw";
10
+    Lang["ZH_HK"] = "zh-hk";
11
+    Lang["EN"] = "en";
12
+    Lang["ID"] = "id";
13
+    Lang["JA"] = "ja";
14
+    Lang["KO"] = "ko";
15
+    Lang["RU"] = "ru";
16
+    Lang["AR"] = "ar";
17
+    Lang["ES"] = "es";
18
+    Lang["PT_PT"] = "pt-pt";
19
+    Lang["FR"] = "fr";
20
+    Lang["DE"] = "de";
21
+})(Lang || (Lang = {}));
22
+export var BackgroundBlurEffectIOS;
23
+(function (BackgroundBlurEffectIOS) {
24
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["None"] = -1] = "None";
25
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["ExtraLight"] = 0] = "ExtraLight";
26
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Light"] = 1] = "Light";
27
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Dark"] = 2] = "Dark";
28
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Regular"] = 3] = "Regular";
29
+    BackgroundBlurEffectIOS[BackgroundBlurEffectIOS["Prominent"] = 4] = "Prominent";
30
+})(BackgroundBlurEffectIOS || (BackgroundBlurEffectIOS = {}));
31
+export const start = RNGSModule.start;
32
+export const stop = RNGSModule.stop;
33
+export const addListener = (listener) => RNGSEventEmitter.addListener(EventName, listener);
34
+export function parseOption(o, defaultOption) {
35
+    const option = Object.assign({}, defaultOption);
36
+    option.api1Result = JSON.stringify(o.api1Result);
37
+    if (typeof o.debug === "boolean") {
38
+        option.debug = o.debug;
39
+    }
40
+    if (typeof o.loadTimeout === "number") {
41
+        option.loadTimeout = o.loadTimeout >> 0;
42
+    }
43
+    if (typeof o.reqTimeout === "number") {
44
+        option.reqTimeout = o.reqTimeout >> 0;
45
+    }
46
+    if (typeof o.lang === "string") {
47
+        option.lang = o.lang;
48
+    }
49
+    if (typeof o.enableBackgroundCancel === "boolean") {
50
+        option.enableBackgroundCancel = o.enableBackgroundCancel;
51
+    }
52
+    if (o.backgroundColorIOS !== undefined) {
53
+        option.backgroundColorIOS = processColor(o.backgroundColorIOS);
54
+    }
55
+    if (typeof o.backgroundBlurEffectIOS === "number") {
56
+        option.backgroundBlurEffectIOS = o.backgroundBlurEffectIOS;
57
+    }
58
+    return option;
59
+}

BIN
doc/images/ios-add-framework-search-paths.png View File


+ 0
- 201
index.ts View File

@@ -1,201 +0,0 @@
1
-import {
2
-    NativeModules,
3
-    NativeEventEmitter,
4
-    EmitterSubscription,
5
-    Platform,
6
-    processColor
7
-} from 'react-native'
8
-
9
-const Exception = Error
10
-
11
-namespace RNLGeetestSensebot {
12
-    export type Option = Pick<GeetestSensebot.Option,
13
-        'debug' | 'loadTimeout' | 'reqTimeout' | 'enableBackgroundCancel'> & {
14
-        api1Result: string;
15
-        lang?: string;
16
-        backgroundColorIOS?: number;
17
-        backgroundBlurEffectIOS?: number;
18
-    }
19
-
20
-    // API
21
-    const RNLGeetestSensebot = NativeModules.RNLGeetestSensebot
22
-
23
-    export const start: (obj: Option) => void = RNLGeetestSensebot.start
24
-
25
-    export const stop: () => void = RNLGeetestSensebot.stop
26
-
27
-    // Event
28
-    const EventName = 'RNLGeetestSensebotEvent'
29
-
30
-    const EventEmitter = new NativeEventEmitter(RNLGeetestSensebot)
31
-
32
-    export const addListener = (listener: (data: any) => void) =>
33
-        EventEmitter.addListener(EventName, listener)
34
-}
35
-
36
-namespace GeetestSensebot {
37
-    export enum Lang {
38
-        System = 'system', // 跟随系统
39
-        ZH = 'zh', // 简体中文
40
-        ZH_TW = 'zh-tw', // 繁体中文
41
-        ZH_HK = 'zh-hk', // 繁体中文
42
-        EN = 'en', // 英语
43
-        ID = 'id', // 印尼语
44
-        JA = 'ja', // 日语
45
-        KO = 'ko', // 韩语
46
-        RU = 'ru', // 俄语
47
-        AR = 'ar', // 阿拉伯语
48
-        ES = 'es', // 西班牙语
49
-        PT_PT = 'pt-pt', // 葡萄牙语
50
-        FR = 'fr', // 法语
51
-        DE = 'de', // 德语
52
-    }
53
-
54
-    export enum BackgroundBlurEffectIOS {
55
-        None = -1,
56
-        ExtraLight = 0,
57
-        Light,
58
-        Dark,
59
-        Regular, // NS_ENUM_AVAILABLE_IOS(10_0)
60
-        Prominent, // NS_ENUM_AVAILABLE_IOS(10_0)
61
-    }
62
-
63
-    export interface Option {
64
-        // API1
65
-        api1Result: API1Result;
66
-        // debug
67
-        debug?: boolean;
68
-        // view 加载超时时间,默认10000
69
-        loadTimeout?: number;
70
-        // 第二步向极验服务器发送请求超时时间,默认10000
71
-        reqTimeout?: number;
72
-        // 语言,如果为null则使用系统默认语言
73
-        lang?: Lang;
74
-        // 点击背景是否可以取消验证
75
-        enableBackgroundCancel?: boolean;
76
-        // 背景色 IOS Only
77
-        backgroundColorIOS?: any;
78
-        // 背景模糊类型 IOS Only
79
-        backgroundBlurEffectIOS?: BackgroundBlurEffectIOS;
80
-        // 事件监听
81
-        onEvent?: (code: Event, data?: Array<number | string>) => void;
82
-    }
83
-
84
-    export interface API1Result {
85
-        success: 0 | 1;
86
-        challenge: string;
87
-        gt: string;
88
-        new_captcha: boolean;
89
-        [key: string]: any;
90
-    }
91
-
92
-    export interface Result {
93
-        geetest_challenge: string;
94
-        geetest_seccode: string;
95
-        geetest_validate: string;
96
-        [key: string]: any;
97
-    }
98
-
99
-    export enum Event {
100
-        // 验证结果
101
-        RESULT = 1,
102
-        // 验证窗口关闭
103
-        CLOSED = 2,
104
-        // 验证失败
105
-        FAILED = 3,
106
-        // 发生错误
107
-        ERROR = 0,
108
-    }
109
-
110
-    export enum Error {
111
-        // 参数解析错误
112
-        PARAMETER_PARSE_FAILED = -1,
113
-        // 安卓 activity 已经销毁
114
-        ANDROID_ACTIVITY_DESTROYED = -2,
115
-    }
116
-
117
-    const defaultOption: RNLGeetestSensebot.Option = {
118
-        api1Result: '',
119
-        debug: false,
120
-        loadTimeout: 10000,
121
-        reqTimeout: 10000,
122
-        lang: Lang.System,
123
-        enableBackgroundCancel: false,
124
-        backgroundColorIOS: 0, // processColor('transparent')
125
-        backgroundBlurEffectIOS: BackgroundBlurEffectIOS.None,
126
-    }
127
-
128
-    function parseConfig(c: Option): RNLGeetestSensebot.Option {
129
-        const config = Object.assign({}, defaultOption)
130
-
131
-        config.api1Result = JSON.stringify(c.api1Result)
132
-        if (typeof c.debug === 'boolean') {
133
-            config.debug = c.debug
134
-        }
135
-        if (typeof c.loadTimeout === 'number') {
136
-            config.loadTimeout = c.loadTimeout >> 0
137
-        }
138
-        if (typeof c.reqTimeout === 'number') {
139
-            config.reqTimeout = c.reqTimeout >> 0
140
-        }
141
-        if (typeof c.lang === 'string') {
142
-            config.lang = c.lang
143
-        }
144
-        if (typeof c.enableBackgroundCancel === 'boolean') {
145
-            config.enableBackgroundCancel = c.enableBackgroundCancel
146
-        }
147
-        if (c.backgroundColorIOS !== undefined) {
148
-            config.backgroundColorIOS = processColor(c.backgroundColorIOS)
149
-        }
150
-        if (typeof c.backgroundBlurEffectIOS === 'number') {
151
-            config.backgroundBlurEffectIOS = c.backgroundBlurEffectIOS
152
-        }
153
-
154
-        return config
155
-    }
156
-
157
-    let eventListener: EmitterSubscription
158
-
159
-    // 进行行为认证
160
-    export function start(option: Option): Promise<Result> {
161
-        return new Promise((resolve, reject) => {
162
-            eventListener = RNLGeetestSensebot.addListener(([code, ...data]) => {
163
-                switch (code) {
164
-                    case Event.RESULT:
165
-                        stop()
166
-                        resolve(JSON.parse(data[0]))
167
-                        break
168
-                    case Event.FAILED:
169
-                        // iOS 只要认证错误就会触发, android 多次认证错误最后自动关闭 view 时才会触发
170
-                        if (Platform.OS === 'android') {
171
-                            stop()
172
-                        }
173
-                        break
174
-                    case Event.ERROR:
175
-                        stop()
176
-                        const error = new Exception(data[1])
177
-                        Object.defineProperty(error, 'name',
178
-                            { value: 'RNGeetestError', writable: false })
179
-                        Object.defineProperty(error, 'code',
180
-                            { value: data[0], writable: false })
181
-                        reject(error)
182
-                        break
183
-                }
184
-                if (typeof option.onEvent === 'function') {
185
-                    option.onEvent(code, data)
186
-                }
187
-            })
188
-            RNLGeetestSensebot.start(parseConfig(option))
189
-        })
190
-    }
191
-
192
-    // 清理行为认证资源占用
193
-    export function stop () {
194
-        if (eventListener && typeof eventListener.remove === 'function') {
195
-            eventListener.remove()
196
-        }
197
-        RNLGeetestSensebot.stop()
198
-    }
199
-}
200
-
201
-export default GeetestSensebot

+ 0
- 8
ios/RNLGeetestSensebot.h View File

@@ -1,13 +1,5 @@
1
-#if __has_include(<React/RCTBridgeModule.h>)
2 1
 #import <React/RCTBridgeModule.h>
3
-#else
4
-#import "RCTBridgeModule.h"
5
-#endif
6
-#if __has_include(<React/RCTEventEmitter.h>)
7 2
 #import <React/RCTEventEmitter.h>
8
-#else
9
-#import "RCTEventEmitter.h"
10
-#endif
11 3
 
12 4
 @interface RNLGeetestSensebot : RCTEventEmitter <RCTBridgeModule>
13 5
 @end

+ 30
- 37
ios/RNLGeetestSensebot.m View File

@@ -1,19 +1,9 @@
1
-#if __has_include(<React/RCTConvert.h>)
1
+#import <GT3Captcha/GT3Captcha.h>
2 2
 #import <React/RCTConvert.h>
3
-#else
4
-#import "RCTConvert.h"
5
-#endif
6
-#if __has_include(<React/RCTUtils.h>)
7 3
 #import <React/RCTUtils.h>
8
-#else
9
-#import "RCTUtils.h"
10
-#endif
11
-#import <GT3Captcha/GT3Captcha.h>
12 4
 
13 5
 #import "RNLGeetestSensebot.h"
14 6
 
15
-static NSString* EventName = @"RNLGeetestSensebotEvent";
16
-
17 7
 typedef NS_ENUM(NSUInteger, RNLGSEvent) {
18 8
     RNLGSResultEvent = 1,
19 9
     RNLGSClosedEvent = 2,
@@ -42,18 +32,21 @@ static NSNumber* RNLGSGetErrorCode(RNLGSError event) {
42 32
 
43 33
 RCT_EXPORT_METHOD(start:(NSDictionary *)option)
44 34
 {
35
+    if (_manager == nil) {
36
+        _manager = [GT3CaptchaManager alloc];
37
+        _manager.delegate = self;
38
+        _manager.viewDelegate = self;
39
+    }
45 40
     @try {
46 41
         // view load timeout
47
-        NSTimeInterval timeout = [RCTConvert double:option[@"loadTimeout"]] / 1000.0;
42
+        NSTimeInterval timeout = [RCTConvert NSTimeInterval:option[@"loadTimeout"]];
48 43
         // init manager
49
-        _manager = [[GT3CaptchaManager alloc] initWithAPI1:nil API2:nil timeout:timeout];
50
-        _manager.delegate = self;
51
-        _manager.viewDelegate = self;
44
+        _manager = [_manager initWithAPI1:nil API2:nil timeout:timeout];
52 45
         // debug
53 46
         BOOL enableDebugMode = [RCTConvert BOOL:option[@"debug"]];
54 47
         [_manager enableDebugMode: enableDebugMode];
55 48
         // request timeout
56
-        NSTimeInterval gtViewTimeout = [RCTConvert double:option[@"reqTimeout"]] / 1000.0;
49
+        NSTimeInterval gtViewTimeout = [RCTConvert NSTimeInterval:option[@"reqTimeout"]];
57 50
         [_manager useGTViewWithTimeout:gtViewTimeout];
58 51
         // lang
59 52
         GT3LanguageType lang = [RNLGeetestSensebot parseLanguag:
@@ -80,9 +73,6 @@ RCT_EXPORT_METHOD(start:(NSDictionary *)option)
80 73
                        challenge:[api1JSON objectForKey:@"challenge"]
81 74
                          success:[api1JSON objectForKey:@"success"]
82 75
                         withAPI2:nil];
83
-        // registe and start validate
84
-        [_manager registerCaptcha:nil];
85
-        [_manager startGTCaptchaWithAnimated:YES];
86 76
     } @catch (NSException *e) {
87 77
         NSMutableString *errorMessage = [NSMutableString new];
88 78
         [errorMessage appendString:[e name]];
@@ -96,14 +86,20 @@ RCT_EXPORT_METHOD(start:(NSDictionary *)option)
96 86
                           RNLGSGetEventCode(RNLGSErrorEvent),
97 87
                           RNLGSGetErrorCode(RNLGSParameterParseError),
98 88
                           errorMessage]];
89
+        return;
99 90
     }
91
+    // registe and start validate
92
+    [_manager registerCaptcha:nil];
93
+    dispatch_async(dispatch_get_main_queue(), ^{
94
+        [_manager startGTCaptchaWithAnimated:YES];
95
+    });
100 96
 }
101 97
 
102
-RCT_EXPORT_METHOD(stop)
98
+RCT_EXPORT_METHOD(stop:(RCTResponseSenderBlock)callback)
103 99
 {
104 100
     if (_manager != nil) {
105 101
         [_manager stopGTCaptcha];
106
-        _manager = nil;
102
+        callback(nil);
107 103
     }
108 104
 }
109 105
 
@@ -155,18 +151,18 @@ RCT_EXPORT_METHOD(stop)
155 151
 
156 152
 - (void)gtCaptcha:(GT3CaptchaManager *)manager didReceiveCaptchaCode:(NSString *)code result:(NSDictionary *)result message:(NSString *)message
157 153
 {
158
-    if ([code isEqualToString:@"0"]) {
159
-        [self sendEvent:@[RNLGSGetEventCode(RNLGSFailedEvent),
160
-                          RCTJSONStringify(result, nil)]];
161
-    } else if ([code isEqualToString:@"1"]) {
154
+    if ([code isEqualToString:@"1"]) {
162 155
         [self sendEvent:@[RNLGSGetEventCode(RNLGSResultEvent),
163 156
                           RCTJSONStringify(result, nil)]];
157
+    } else if ([code isEqualToString:@"0"] && [result count] > 1) {
158
+        // code == 0 代表失败, 用户滑动不准确时也会触发这个条件, 过滤 dict 里面字段数量为 1 时的信息
159
+        [self sendEvent:@[RNLGSGetEventCode(RNLGSFailedEvent),
160
+                          RCTJSONStringify(result, nil)]];
164 161
     }
165 162
 }
166 163
 
167 164
 - (void)gtCaptcha:(GT3CaptchaManager *)manager didReceiveSecondaryCaptchaData:(NSData *)data response:(NSURLResponse *)response error:(GT3Error *)error decisionHandler:(void (^)(GT3SecondaryCaptchaPolicy))decisionHandler
168 165
 {
169
-
170 166
 }
171 167
 
172 168
 - (void)gtCaptchaUserDidCloseGTView:(GT3CaptchaManager *)manager
@@ -186,26 +182,23 @@ RCT_EXPORT_METHOD(stop)
186 182
 
187 183
 #pragma react native bridge
188 184
 
189
-- (NSArray<NSString *> *)supportedEvents
190
-{
191
-    return @[EventName];
192
-}
185
+RCT_EXPORT_MODULE(RNLGeetestSensebot)
193 186
 
194
-- (void)sendEvent:(id)body
187
++ (BOOL)requiresMainQueueSetup
195 188
 {
196
-    [self sendEventWithName:EventName body:body];
189
+    return NO;
197 190
 }
198 191
 
199
-RCT_EXPORT_MODULE()
192
+static NSString* EventName = @"RNLGeetestSensebotEvent";
200 193
 
201
-+ (BOOL)requiresMainQueueSetup
194
+- (NSArray<NSString *> *)supportedEvents
202 195
 {
203
-    return YES;
196
+    return @[EventName];
204 197
 }
205 198
 
206
-- (dispatch_queue_t)methodQueue
199
+- (void)sendEvent:(id)body
207 200
 {
208
-    return dispatch_get_main_queue();
201
+    [self sendEventWithName:EventName body:body];
209 202
 }
210 203
 
211 204
 @end

+ 32
- 8
ios/RNLGeetestSensebot.xcodeproj/project.pbxproj View File

@@ -7,14 +7,29 @@
7 7
 	objects = {
8 8
 
9 9
 /* Begin PBXBuildFile section */
10
-		363F8FBF226ED46600C89882 /* GT3Captcha.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 363F8FBD226ED42100C89882 /* GT3Captcha.bundle */; };
10
+		363172872276D1CF0084C7FB /* GT3Captcha.bundle in Resources */ = {isa = PBXBuildFile; fileRef = 363F8FBD226ED42100C89882 /* GT3Captcha.bundle */; };
11
+		363173142276ED120084C7FB /* GT3Captcha.framework in Copy Frameworks */ = {isa = PBXBuildFile; fileRef = 363173132276ECDE0084C7FB /* GT3Captcha.framework */; };
11 12
 		B3E7B58A1CC2AC0600A0062D /* RNLGeetestSensebot.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNLGeetestSensebot.m */; };
12 13
 /* End PBXBuildFile section */
13 14
 
15
+/* Begin PBXCopyFilesBuildPhase section */
16
+		3631730F2276ECB60084C7FB /* Copy Frameworks */ = {
17
+			isa = PBXCopyFilesBuildPhase;
18
+			buildActionMask = 2147483647;
19
+			dstPath = .;
20
+			dstSubfolderSpec = 16;
21
+			files = (
22
+				363173142276ED120084C7FB /* GT3Captcha.framework in Copy Frameworks */,
23
+			);
24
+			name = "Copy Frameworks";
25
+			runOnlyForDeploymentPostprocessing = 0;
26
+		};
27
+/* End PBXCopyFilesBuildPhase section */
28
+
14 29
 /* Begin PBXFileReference section */
15 30
 		134814201AA4EA6300B7C361 /* libRNLGeetestSensebot.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNLGeetestSensebot.a; sourceTree = BUILT_PRODUCTS_DIR; };
16
-		363F8FBD226ED42100C89882 /* GT3Captcha.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; path = GT3Captcha.bundle; sourceTree = "<group>"; };
17
-		363F8FBE226ED45600C89882 /* GT3Captcha.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GT3Captcha.framework; path = SDK/GT3Captcha.framework; sourceTree = "<group>"; };
31
+		363173132276ECDE0084C7FB /* GT3Captcha.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GT3Captcha.framework; path = SDK/GT3Captcha.framework; sourceTree = "<group>"; };
32
+		363F8FBD226ED42100C89882 /* GT3Captcha.bundle */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.plug-in"; name = GT3Captcha.bundle; path = SDK/GT3Captcha.bundle; sourceTree = "<group>"; };
18 33
 		B3E7B5881CC2AC0600A0062D /* RNLGeetestSensebot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNLGeetestSensebot.h; sourceTree = "<group>"; };
19 34
 		B3E7B5891CC2AC0600A0062D /* RNLGeetestSensebot.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNLGeetestSensebot.m; sourceTree = "<group>"; };
20 35
 /* End PBXFileReference section */
@@ -28,13 +43,20 @@
28 43
 			name = Products;
29 44
 			sourceTree = "<group>";
30 45
 		};
31
-		363F8FBC226ED41C00C89882 /* SDK */ = {
46
+		363172862276D1350084C7FB /* Resources */ = {
32 47
 			isa = PBXGroup;
33 48
 			children = (
34
-				363F8FBE226ED45600C89882 /* GT3Captcha.framework */,
35 49
 				363F8FBD226ED42100C89882 /* GT3Captcha.bundle */,
36 50
 			);
37
-			name = SDK;
51
+			name = Resources;
52
+			sourceTree = "<group>";
53
+		};
54
+		363173122276ECD40084C7FB /* Frameworks */ = {
55
+			isa = PBXGroup;
56
+			children = (
57
+				363173132276ECDE0084C7FB /* GT3Captcha.framework */,
58
+			);
59
+			name = Frameworks;
38 60
 			sourceTree = "<group>";
39 61
 		};
40 62
 		58B511D21A9E6C8500147676 = {
@@ -42,7 +64,8 @@
42 64
 			children = (
43 65
 				B3E7B5881CC2AC0600A0062D /* RNLGeetestSensebot.h */,
44 66
 				B3E7B5891CC2AC0600A0062D /* RNLGeetestSensebot.m */,
45
-				363F8FBC226ED41C00C89882 /* SDK */,
67
+				363172862276D1350084C7FB /* Resources */,
68
+				363173122276ECD40084C7FB /* Frameworks */,
46 69
 				134814211AA4EA7D00B7C361 /* Products */,
47 70
 			);
48 71
 			sourceTree = "<group>";
@@ -56,6 +79,7 @@
56 79
 			buildPhases = (
57 80
 				58B511D71A9E6C8500147676 /* Sources */,
58 81
 				363F8F8C226ED25100C89882 /* Resources */,
82
+				3631730F2276ECB60084C7FB /* Copy Frameworks */,
59 83
 			);
60 84
 			buildRules = (
61 85
 			);
@@ -103,7 +127,7 @@
103 127
 			isa = PBXResourcesBuildPhase;
104 128
 			buildActionMask = 2147483647;
105 129
 			files = (
106
-				363F8FBF226ED46600C89882 /* GT3Captcha.bundle in Resources */,
130
+				363172872276D1CF0084C7FB /* GT3Captcha.bundle in Resources */,
107 131
 			);
108 132
 			runOnlyForDeploymentPostprocessing = 0;
109 133
 		};

+ 296
- 4
package-lock.json View File

@@ -4,10 +4,25 @@
4 4
   "lockfileVersion": 1,
5 5
   "requires": true,
6 6
   "dependencies": {
7
-    "@types/invariant": {
8
-      "version": "2.2.29",
9
-      "resolved": "https://registry.npmjs.org/@types/invariant/-/invariant-2.2.29.tgz",
10
-      "integrity": "sha512-lRVw09gOvgviOfeUrKc/pmTiRZ7g7oDOU6OAutyuSHpm1/o2RaBQvRhgK8QEdu+FFuw/wnWb29A/iuxv9i8OpQ=="
7
+    "@babel/code-frame": {
8
+      "version": "7.0.0",
9
+      "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.0.0.tgz",
10
+      "integrity": "sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==",
11
+      "dev": true,
12
+      "requires": {
13
+        "@babel/highlight": "^7.0.0"
14
+      }
15
+    },
16
+    "@babel/highlight": {
17
+      "version": "7.0.0",
18
+      "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.0.0.tgz",
19
+      "integrity": "sha512-UFMC4ZeFC48Tpvj7C8UgLvtkaUuovQX+5xNWrsIoMG8o2z+XFKjKaN9iVmS84dPwVN00W4wPmqvYoZF3EGAsfw==",
20
+      "dev": true,
21
+      "requires": {
22
+        "chalk": "^2.0.0",
23
+        "esutils": "^2.0.2",
24
+        "js-tokens": "^4.0.0"
25
+      }
11 26
     },
12 27
     "@types/prop-types": {
13 28
       "version": "15.7.1",
@@ -32,16 +47,293 @@
32 47
         "@types/react": "*"
33 48
       }
34 49
     },
50
+    "ansi-styles": {
51
+      "version": "3.2.1",
52
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
53
+      "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
54
+      "dev": true,
55
+      "requires": {
56
+        "color-convert": "^1.9.0"
57
+      }
58
+    },
59
+    "argparse": {
60
+      "version": "1.0.10",
61
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
62
+      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
63
+      "dev": true,
64
+      "requires": {
65
+        "sprintf-js": "~1.0.2"
66
+      }
67
+    },
68
+    "balanced-match": {
69
+      "version": "1.0.0",
70
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
71
+      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
72
+      "dev": true
73
+    },
74
+    "brace-expansion": {
75
+      "version": "1.1.11",
76
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
77
+      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
78
+      "dev": true,
79
+      "requires": {
80
+        "balanced-match": "^1.0.0",
81
+        "concat-map": "0.0.1"
82
+      }
83
+    },
84
+    "builtin-modules": {
85
+      "version": "1.1.1",
86
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
87
+      "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
88
+      "dev": true
89
+    },
90
+    "chalk": {
91
+      "version": "2.4.2",
92
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
93
+      "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
94
+      "dev": true,
95
+      "requires": {
96
+        "ansi-styles": "^3.2.1",
97
+        "escape-string-regexp": "^1.0.5",
98
+        "supports-color": "^5.3.0"
99
+      }
100
+    },
101
+    "color-convert": {
102
+      "version": "1.9.3",
103
+      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
104
+      "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
105
+      "dev": true,
106
+      "requires": {
107
+        "color-name": "1.1.3"
108
+      }
109
+    },
110
+    "color-name": {
111
+      "version": "1.1.3",
112
+      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
113
+      "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
114
+      "dev": true
115
+    },
116
+    "commander": {
117
+      "version": "2.20.0",
118
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
119
+      "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==",
120
+      "dev": true
121
+    },
122
+    "concat-map": {
123
+      "version": "0.0.1",
124
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
125
+      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
126
+      "dev": true
127
+    },
35 128
     "csstype": {
36 129
       "version": "2.6.4",
37 130
       "resolved": "https://registry.npmjs.org/csstype/-/csstype-2.6.4.tgz",
38 131
       "integrity": "sha512-lAJUJP3M6HxFXbqtGRc0iZrdyeN+WzOWeY0q/VnFzI+kqVrYIzC7bWlKqCW7oCIdzoPkvfp82EVvrTlQ8zsWQg=="
39 132
     },
133
+    "diff": {
134
+      "version": "3.5.0",
135
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz",
136
+      "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==",
137
+      "dev": true
138
+    },
139
+    "escape-string-regexp": {
140
+      "version": "1.0.5",
141
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
142
+      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
143
+      "dev": true
144
+    },
145
+    "esprima": {
146
+      "version": "4.0.1",
147
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
148
+      "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==",
149
+      "dev": true
150
+    },
151
+    "esutils": {
152
+      "version": "2.0.2",
153
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
154
+      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
155
+      "dev": true
156
+    },
157
+    "fs.realpath": {
158
+      "version": "1.0.0",
159
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
160
+      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
161
+      "dev": true
162
+    },
163
+    "glob": {
164
+      "version": "7.1.3",
165
+      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
166
+      "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==",
167
+      "dev": true,
168
+      "requires": {
169
+        "fs.realpath": "^1.0.0",
170
+        "inflight": "^1.0.4",
171
+        "inherits": "2",
172
+        "minimatch": "^3.0.4",
173
+        "once": "^1.3.0",
174
+        "path-is-absolute": "^1.0.0"
175
+      }
176
+    },
177
+    "has-flag": {
178
+      "version": "3.0.0",
179
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
180
+      "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
181
+      "dev": true
182
+    },
183
+    "inflight": {
184
+      "version": "1.0.6",
185
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
186
+      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
187
+      "dev": true,
188
+      "requires": {
189
+        "once": "^1.3.0",
190
+        "wrappy": "1"
191
+      }
192
+    },
193
+    "inherits": {
194
+      "version": "2.0.3",
195
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
196
+      "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
197
+      "dev": true
198
+    },
199
+    "js-tokens": {
200
+      "version": "4.0.0",
201
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
202
+      "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
203
+      "dev": true
204
+    },
205
+    "js-yaml": {
206
+      "version": "3.13.1",
207
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz",
208
+      "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==",
209
+      "dev": true,
210
+      "requires": {
211
+        "argparse": "^1.0.7",
212
+        "esprima": "^4.0.0"
213
+      }
214
+    },
215
+    "minimatch": {
216
+      "version": "3.0.4",
217
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
218
+      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
219
+      "dev": true,
220
+      "requires": {
221
+        "brace-expansion": "^1.1.7"
222
+      }
223
+    },
224
+    "minimist": {
225
+      "version": "0.0.8",
226
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
227
+      "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
228
+      "dev": true
229
+    },
230
+    "mkdirp": {
231
+      "version": "0.5.1",
232
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
233
+      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
234
+      "dev": true,
235
+      "requires": {
236
+        "minimist": "0.0.8"
237
+      }
238
+    },
239
+    "once": {
240
+      "version": "1.4.0",
241
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
242
+      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
243
+      "dev": true,
244
+      "requires": {
245
+        "wrappy": "1"
246
+      }
247
+    },
248
+    "path-is-absolute": {
249
+      "version": "1.0.1",
250
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
251
+      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
252
+      "dev": true
253
+    },
254
+    "path-parse": {
255
+      "version": "1.0.6",
256
+      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
257
+      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==",
258
+      "dev": true
259
+    },
260
+    "resolve": {
261
+      "version": "1.10.1",
262
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.10.1.tgz",
263
+      "integrity": "sha512-KuIe4mf++td/eFb6wkaPbMDnP6kObCaEtIDuHOUED6MNUo4K670KZUHuuvYPZDxNF0WVLw49n06M2m2dXphEzA==",
264
+      "dev": true,
265
+      "requires": {
266
+        "path-parse": "^1.0.6"
267
+      }
268
+    },
269
+    "semver": {
270
+      "version": "5.7.0",
271
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
272
+      "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==",
273
+      "dev": true
274
+    },
275
+    "sprintf-js": {
276
+      "version": "1.0.3",
277
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
278
+      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
279
+      "dev": true
280
+    },
281
+    "supports-color": {
282
+      "version": "5.5.0",
283
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
284
+      "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
285
+      "dev": true,
286
+      "requires": {
287
+        "has-flag": "^3.0.0"
288
+      }
289
+    },
290
+    "tslib": {
291
+      "version": "1.9.3",
292
+      "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
293
+      "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==",
294
+      "dev": true
295
+    },
296
+    "tslint": {
297
+      "version": "5.16.0",
298
+      "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.16.0.tgz",
299
+      "integrity": "sha512-UxG2yNxJ5pgGwmMzPMYh/CCnCnh0HfPgtlVRDs1ykZklufFBL1ZoTlWFRz2NQjcoEiDoRp+JyT0lhBbbH/obyA==",
300
+      "dev": true,
301
+      "requires": {
302
+        "@babel/code-frame": "^7.0.0",
303
+        "builtin-modules": "^1.1.1",
304
+        "chalk": "^2.3.0",
305
+        "commander": "^2.12.1",
306
+        "diff": "^3.2.0",
307
+        "glob": "^7.1.1",
308
+        "js-yaml": "^3.13.0",
309
+        "minimatch": "^3.0.4",
310
+        "mkdirp": "^0.5.1",
311
+        "resolve": "^1.3.2",
312
+        "semver": "^5.3.0",
313
+        "tslib": "^1.8.0",
314
+        "tsutils": "^2.29.0"
315
+      }
316
+    },
317
+    "tsutils": {
318
+      "version": "2.29.0",
319
+      "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
320
+      "integrity": "sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA==",
321
+      "dev": true,
322
+      "requires": {
323
+        "tslib": "^1.8.1"
324
+      }
325
+    },
40 326
     "typescript": {
41 327
       "version": "3.4.3",
42 328
       "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.3.tgz",
43 329
       "integrity": "sha512-FFgHdPt4T/duxx6Ndf7hwgMZZjZpB+U0nMNGVCYPq0rEzWKjEDobm4J6yb3CS7naZ0yURFqdw9Gwc7UOh/P9oQ==",
44 330
       "dev": true
331
+    },
332
+    "wrappy": {
333
+      "version": "1.0.2",
334
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
335
+      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
336
+      "dev": true
45 337
     }
46 338
   }
47 339
 }

+ 20
- 13
package.json View File

@@ -1,31 +1,38 @@
1 1
 {
2 2
   "name": "@yyyyu/react-native-geetest-sensebot",
3
-  "author": "yyyyu <g592842897@gmail.com>",
4
-  "version": "2.0.0",
3
+  "version": "2.1.0",
4
+  "description": "geetest sensebot for react native.",
5 5
   "keywords": [
6 6
     "react-native",
7 7
     "geetest sensebot"
8 8
   ],
9
-  "description": "geetest sensebot for react native.",
10
-  "license": "MIT",
11 9
   "homepage": "https://github.com/yyyyu/react-native-geetest-sensebot",
12
-  "repository": {
13
-    "type": "git",
14
-    "url": "git@github.com:yyyyu/react-native-geetest-sensebot.git"
10
+  "bugs": {
11
+    "url": "https://github.com/yyyyu/react-native-geetest-sensebot/issues"
12
+  },
13
+  "license": "MIT",
14
+  "author": {
15
+    "name": "yyyyu",
16
+    "email": "g592842897@gmail.com"
15 17
   },
16 18
   "main": "dist/index.js",
17 19
   "types": "dist/index.d.js",
20
+  "repository": {
21
+    "type": "git",
22
+    "url": "https://github.com/yyyyu/react-native-geetest-sensebot.git"
23
+  },
18 24
   "scripts": {
19
-    "build": "tsc"
25
+    "build": "tsc",
26
+    "lint": "tslint --fix ./src/**/*.ts"
20 27
   },
21
-  "peerDependencies": {
22
-    "react-native": "^0.59.5"
28
+  "dependencies": {
29
+    "@types/react-native": "^0.57.45"
23 30
   },
24 31
   "devDependencies": {
32
+    "tslint": "^5.16.0",
25 33
     "typescript": "^3.4.3"
26 34
   },
27
-  "dependencies": {
28
-    "@types/invariant": "^2.2.29",
29
-    "@types/react-native": "^0.57.45"
35
+  "peerDependencies": {
36
+    "react-native": "^0.59.5"
30 37
   }
31 38
 }

+ 137
- 0
src/index.ts View File

@@ -0,0 +1,137 @@
1
+import { EmitterSubscription, Platform } from "react-native";
2
+import * as RNGSModule from "./module";
3
+export { BackgroundBlurEffectIOS, Lang } from "./module";
4
+
5
+export interface IAPI1Result {
6
+    success: 0 | 1;
7
+    challenge: string;
8
+    gt: string;
9
+    new_captcha: boolean;
10
+    [key: string]: any;
11
+}
12
+
13
+export interface IOption {
14
+    // API1
15
+    api1Result: IAPI1Result;
16
+    // debug
17
+    debug?: boolean;
18
+    // view 加载超时时间,默认10000
19
+    loadTimeout?: number;
20
+    // 第二步向极验服务器发送请求超时时间,默认10000
21
+    reqTimeout?: number;
22
+    // 语言
23
+    lang?: RNGSModule.Lang;
24
+    // 点击背景是否可以取消验证
25
+    enableBackgroundCancel?: boolean;
26
+    // 背景色 IOS Only
27
+    backgroundColorIOS?: any;
28
+    // 背景模糊类型 IOS Only
29
+    backgroundBlurEffectIOS?: RNGSModule.BackgroundBlurEffectIOS;
30
+    // 事件监听
31
+    onEvent?: (code: Events, data?: Array<number | string>) => void;
32
+}
33
+
34
+export interface IResult {
35
+    geetest_challenge: string;
36
+    geetest_seccode: string;
37
+    geetest_validate: string;
38
+    [key: string]: any;
39
+}
40
+
41
+export enum Errors {
42
+    // 参数解析错误
43
+    PARAMETER_PARSE_FAILED = -1,
44
+    // 安卓 activity 已经销毁
45
+    ANDROID_ACTIVITY_DESTROYED = -2,
46
+    // 重复运行
47
+    DUPLICATE_START = -3,
48
+}
49
+
50
+export enum Events {
51
+    // 验证结果
52
+    RESULT = 1,
53
+    // 验证窗口关闭
54
+    CLOSED = 2,
55
+    // 验证失败
56
+    FAILED = 3,
57
+    // 发生错误
58
+    ERROR = 0,
59
+}
60
+
61
+enum InternalStatus {
62
+    None = 0b0,
63
+    // 认证中
64
+    Running = 0b1,
65
+    // 停止认证中
66
+    Stoping = 0b1 >> 1,
67
+}
68
+
69
+let internalStatus = InternalStatus.None;
70
+let eventListener: EmitterSubscription | null = null;
71
+
72
+const DEFAULT_OPTION = {
73
+    api1Result: "",
74
+    debug: false,
75
+    loadTimeout: 10000,
76
+    reqTimeout: 10000,
77
+    lang: RNGSModule.Lang.System,
78
+    enableBackgroundCancel: false,
79
+    backgroundColorIOS: 0, // processColor('transparent')
80
+    backgroundBlurEffectIOS: RNGSModule.BackgroundBlurEffectIOS.None,
81
+};
82
+
83
+// 进行行为认证
84
+export function start(option: IOption): Promise<IResult> {
85
+    return new Promise((resolve, reject) => {
86
+        if (internalStatus & InternalStatus.Running) {
87
+            return reject(new GeetestError(
88
+                Errors.DUPLICATE_START, "Duplicate start"));
89
+        }
90
+        internalStatus |= InternalStatus.Running;
91
+        eventListener = RNGSModule.addListener(([code, ...data]) => {
92
+            switch (code) {
93
+                case Events.RESULT:
94
+                    resolve(JSON.parse(data[0]));
95
+                    stop();
96
+                    break;
97
+                case Events.FAILED:
98
+                case Events.CLOSED:
99
+                    stop();
100
+                    break;
101
+                case Events.ERROR:
102
+                    reject(new GeetestError(data[0], data[1]));
103
+                    stop();
104
+                    break;
105
+            }
106
+            if (typeof option.onEvent === "function") {
107
+                option.onEvent(code, data);
108
+            }
109
+        });
110
+        RNGSModule.start(RNGSModule.parseOption(option, DEFAULT_OPTION));
111
+    });
112
+}
113
+
114
+function stop() {
115
+    if (internalStatus & InternalStatus.Stoping) { return; }
116
+    internalStatus |= InternalStatus.Stoping;
117
+    RNGSModule.stop(() => {
118
+        internalStatus = InternalStatus.None;
119
+        if (eventListener && typeof eventListener.remove === "function") {
120
+            eventListener.remove();
121
+            eventListener = null;
122
+        }
123
+    });
124
+}
125
+
126
+export class GeetestError extends Error {
127
+    constructor(readonly code: number, readonly message: string) {
128
+        super(message);
129
+
130
+        // @ts-ignore
131
+        if (Error.captureStackTrace) {
132
+            // @ts-ignore
133
+            Error.captureStackTrace(this, GeetestError);
134
+        }
135
+        this.name = "GeetestError";
136
+    }
137
+}

+ 80
- 0
src/module.ts View File

@@ -0,0 +1,80 @@
1
+import { NativeEventEmitter, NativeModules, processColor } from "react-native";
2
+
3
+const RNGSModule = NativeModules.RNLGeetestSensebot;
4
+const RNGSEventEmitter = new NativeEventEmitter(RNGSModule);
5
+const EventName = "RNLGeetestSensebotEvent";
6
+
7
+export enum Lang {
8
+    System = "system", // 跟随系统
9
+    ZH = "zh", // 简体中文
10
+    ZH_TW = "zh-tw", // 繁体中文
11
+    ZH_HK = "zh-hk", // 繁体中文
12
+    EN = "en", // 英语
13
+    ID = "id", // 印尼语
14
+    JA = "ja", // 日语
15
+    KO = "ko", // 韩语
16
+    RU = "ru", // 俄语
17
+    AR = "ar", // 阿拉伯语
18
+    ES = "es", // 西班牙语
19
+    PT_PT = "pt-pt", // 葡萄牙语
20
+    FR = "fr", // 法语
21
+    DE = "de", // 德语
22
+}
23
+
24
+export enum BackgroundBlurEffectIOS {
25
+    None = -1,
26
+    ExtraLight = 0,
27
+    Light,
28
+    Dark,
29
+    Regular, // NS_ENUM_AVAILABLE_IOS(10_0)
30
+    Prominent, // NS_ENUM_AVAILABLE_IOS(10_0)
31
+}
32
+
33
+type Callback = (_: any) => void;
34
+
35
+export const start: (option: IGSOption) => void = RNGSModule.start;
36
+
37
+export const stop: (callback: Callback) => void = RNGSModule.stop;
38
+
39
+export const addListener = (listener: Callback) =>
40
+    RNGSEventEmitter.addListener(EventName, listener);
41
+
42
+interface IGSOption {
43
+    api1Result: string;
44
+    debug: boolean;
45
+    loadTimeout: number;
46
+    reqTimeout: number;
47
+    lang: Lang;
48
+    enableBackgroundCancel: boolean;
49
+    backgroundColorIOS: number;
50
+    backgroundBlurEffectIOS: BackgroundBlurEffectIOS;
51
+}
52
+
53
+export function parseOption(o: any, defaultOption: IGSOption): IGSOption {
54
+    const option = Object.assign({}, defaultOption);
55
+
56
+    option.api1Result = JSON.stringify(o.api1Result);
57
+    if (typeof o.debug === "boolean") {
58
+        option.debug = o.debug;
59
+    }
60
+    if (typeof o.loadTimeout === "number") {
61
+        option.loadTimeout = o.loadTimeout >> 0;
62
+    }
63
+    if (typeof o.reqTimeout === "number") {
64
+        option.reqTimeout = o.reqTimeout >> 0;
65
+    }
66
+    if (typeof o.lang === "string") {
67
+        option.lang = o.lang;
68
+    }
69
+    if (typeof o.enableBackgroundCancel === "boolean") {
70
+        option.enableBackgroundCancel = o.enableBackgroundCancel;
71
+    }
72
+    if (o.backgroundColorIOS !== undefined) {
73
+        option.backgroundColorIOS = processColor(o.backgroundColorIOS);
74
+    }
75
+    if (typeof o.backgroundBlurEffectIOS === "number") {
76
+        option.backgroundBlurEffectIOS = o.backgroundBlurEffectIOS;
77
+    }
78
+
79
+    return option;
80
+}

+ 1
- 1
tsconfig.json View File

@@ -12,7 +12,7 @@
12 12
     // "sourceMap": true,                     /* Generates corresponding '.map' file. */
13 13
     // "outFile": "./",                       /* Concatenate and emit output to single file. */
14 14
     "outDir": "./dist",                        /* Redirect output structure to the directory. */
15
-    // "rootDir": "./",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
15
+    "rootDir": "./src",                       /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
16 16
     // "composite": true,                     /* Enable project compilation */
17 17
     // "incremental": true,                   /* Enable incremental compilation */
18 18
     // "tsBuildInfoFile": "./",               /* Specify file to store incremental compilation information */

+ 12
- 0
tslint.json View File

@@ -0,0 +1,12 @@
1
+{
2
+    "defaultSeverity": "error",
3
+    "extends": [
4
+        "tslint:recommended"
5
+    ],
6
+    "jsRules": {},
7
+    "rules": {
8
+        "no-bitwise": false,
9
+        "object-literal-sort-keys": false
10
+    },
11
+    "rulesDirectory": []
12
+}