index.ts 6.1KB

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