@package-kr/react-native-kakao-signin 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,347 @@
1
+ package com.packagekr.kakao
2
+
3
+ import android.content.pm.PackageManager
4
+ import com.facebook.react.bridge.Arguments
5
+ import com.facebook.react.bridge.Promise
6
+ import com.facebook.react.bridge.ReactApplicationContext
7
+ import com.facebook.react.bridge.ReactMethod
8
+ import com.facebook.react.bridge.WritableMap
9
+ import com.facebook.react.module.annotations.ReactModule
10
+ import com.kakao.sdk.auth.TokenManagerProvider
11
+ import com.kakao.sdk.common.KakaoSdk
12
+ import com.kakao.sdk.common.model.ClientError
13
+ import com.kakao.sdk.common.model.ClientErrorCause
14
+ import com.kakao.sdk.common.util.Utility
15
+ import com.kakao.sdk.user.UserApiClient
16
+ import java.text.SimpleDateFormat
17
+ import java.util.Date
18
+ import java.util.Locale
19
+ import java.util.TimeZone
20
+
21
+ @ReactModule(name = RNKakaoSigninModule.NAME)
22
+ class RNKakaoSigninModule(
23
+ reactContext: ReactApplicationContext
24
+ ) : NativeKakaoLoginSpec(reactContext) {
25
+
26
+ companion object {
27
+ const val NAME = "RNKakaoSignin"
28
+ }
29
+
30
+ init {
31
+ configureKakaoSdk()
32
+ }
33
+
34
+ override fun getName(): String {
35
+ return NAME
36
+ }
37
+
38
+ // SDK 초기화
39
+ private fun configureKakaoSdk() {
40
+ if (KakaoSdk.isInitialized) {
41
+ return
42
+ }
43
+
44
+ val appKey = resolveMetaData("com.kakao.sdk.AppKey")
45
+ ?: resolveString("kakao_app_key")
46
+ ?: return
47
+
48
+ val customScheme = resolveString("kakao_custom_scheme")
49
+
50
+ if (customScheme.isNullOrBlank()) {
51
+ KakaoSdk.init(reactApplicationContext, appKey)
52
+ return
53
+ }
54
+
55
+ KakaoSdk.init(reactApplicationContext, appKey, customScheme)
56
+ }
57
+
58
+ // 카카오톡 로그인
59
+ @ReactMethod
60
+ override fun login(promise: Promise) {
61
+ val activity = currentActivity
62
+
63
+ if (activity == null) {
64
+ promise.reject("E_ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist")
65
+ return
66
+ }
67
+
68
+ if (!UserApiClient.instance.isKakaoTalkLoginAvailable(activity)) {
69
+ loginWithAccount(promise)
70
+ return
71
+ }
72
+
73
+ UserApiClient.instance.loginWithKakaoTalk(activity) { token, error ->
74
+ when {
75
+ token != null -> promise.resolve(resolveToken(token.accessToken, token.refreshToken, token.idToken, token.scopes))
76
+ error is ClientError && error.reason == ClientErrorCause.Cancelled ->
77
+ promise.reject("E_CANCELLED_OPERATION", error.message, error)
78
+ error != null -> loginWithAccount(promise)
79
+ else -> promise.reject("E_UNKNOWN_ERROR", "Login failed")
80
+ }
81
+ }
82
+ }
83
+
84
+ // 카카오계정 로그인
85
+ @ReactMethod
86
+ override fun loginWithKakaoAccount(promise: Promise) {
87
+ loginWithAccount(promise)
88
+ }
89
+
90
+ // 로그아웃
91
+ @ReactMethod
92
+ override fun logout(promise: Promise) {
93
+ UserApiClient.instance.logout { error ->
94
+ if (error != null) {
95
+ promise.reject("E_FAILED_OPERATION", error.message, error)
96
+ return@logout
97
+ }
98
+
99
+ promise.resolve(true)
100
+ }
101
+ }
102
+
103
+ // 연결 해제
104
+ @ReactMethod
105
+ override fun unlink(promise: Promise) {
106
+ UserApiClient.instance.unlink { error ->
107
+ if (error != null) {
108
+ promise.reject("E_FAILED_OPERATION", error.message, error)
109
+ return@unlink
110
+ }
111
+
112
+ promise.resolve(true)
113
+ }
114
+ }
115
+
116
+ // 액세스 토큰 조회
117
+ @ReactMethod
118
+ override fun getAccessToken(promise: Promise) {
119
+ val token = TokenManagerProvider.instance.manager.getToken()
120
+
121
+ if (token == null) {
122
+ promise.resolve(null)
123
+ return
124
+ }
125
+
126
+ promise.resolve(resolveToken(token.accessToken, token.refreshToken, token.idToken, token.scopes))
127
+ }
128
+
129
+ // 프로필 조회
130
+ @ReactMethod
131
+ override fun getProfile(promise: Promise) {
132
+ UserApiClient.instance.me { user, error ->
133
+ if (error != null) {
134
+ promise.reject("E_FAILED_OPERATION", error.message, error)
135
+ return@me
136
+ }
137
+
138
+ if (user == null) {
139
+ promise.reject("E_PROFILE_NOT_FOUND", "Profile not found")
140
+ return@me
141
+ }
142
+
143
+ val profile = Arguments.createMap()
144
+ val account = user.kakaoAccount
145
+ val detail = account?.profile
146
+
147
+ profile.putString("id", user.id?.toString())
148
+ profile.putString("name", account?.name)
149
+ profile.putString("email", account?.email)
150
+ profile.putString("nickname", detail?.nickname)
151
+ profile.putString("profileImageUrl", detail?.profileImageUrl)
152
+ profile.putString("thumbnailImageUrl", detail?.thumbnailImageUrl)
153
+ profile.putString("phoneNumber", account?.phoneNumber)
154
+ profile.putString("ageRange", account?.ageRange?.toString())
155
+ profile.putString("birthday", account?.birthday)
156
+ profile.putString("birthdayType", account?.birthdayType?.toString())
157
+ profile.putString("birthyear", account?.birthyear)
158
+ profile.putString("gender", account?.gender?.toString())
159
+ account?.isEmailValid?.let { profile.putBoolean("isEmailValid", it) }
160
+ account?.isEmailVerified?.let { profile.putBoolean("isEmailVerified", it) }
161
+ account?.isKorean?.let { profile.putBoolean("isKorean", it) }
162
+ account?.hasEmail?.let { profile.putBoolean("hasEmail", it) }
163
+ account?.hasPhoneNumber?.let { profile.putBoolean("hasPhoneNumber", it) }
164
+ account?.hasBirthday?.let { profile.putBoolean("hasBirthday", it) }
165
+ account?.hasBirthyear?.let { profile.putBoolean("hasBirthyear", it) }
166
+ account?.hasAgeRange?.let { profile.putBoolean("hasAgeRange", it) }
167
+ account?.hasGender?.let { profile.putBoolean("hasGender", it) }
168
+ detail?.isDefaultImage?.let { profile.putBoolean("isDefaultImage", it) }
169
+ detail?.isDefaultNickname?.let { profile.putBoolean("isDefaultNickname", it) }
170
+ profile.putString("connectedAt", formatDate(user.connectedAt))
171
+ profile.putString("synchedAt", formatDate(user.synchedAt))
172
+ account?.isLeapMonth?.let { profile.putBoolean("isLeapMonth", it) }
173
+ account?.ci?.let { profile.putString("ci", it) }
174
+ profile.putString("ciAuthenticatedAt", formatDate(account?.ciAuthenticatedAt))
175
+ account?.ageRangeNeedsAgreement?.let { profile.putBoolean("ageRangeNeedsAgreement", it) }
176
+ account?.birthdayNeedsAgreement?.let { profile.putBoolean("birthdayNeedsAgreement", it) }
177
+ account?.birthyearNeedsAgreement?.let { profile.putBoolean("birthyearNeedsAgreement", it) }
178
+ account?.emailNeedsAgreement?.let { profile.putBoolean("emailNeedsAgreement", it) }
179
+ account?.genderNeedsAgreement?.let { profile.putBoolean("genderNeedsAgreement", it) }
180
+ account?.isKoreanNeedsAgreement?.let { profile.putBoolean("isKoreanNeedsAgreement", it) }
181
+ account?.phoneNumberNeedsAgreement?.let { profile.putBoolean("phoneNumberNeedsAgreement", it) }
182
+ account?.profileNeedsAgreement?.let { profile.putBoolean("profileNeedsAgreement", it) }
183
+ account?.profileNicknameNeedsAgreement?.let { profile.putBoolean("profileNicknameNeedsAgreement", it) }
184
+ account?.profileImageNeedsAgreement?.let { profile.putBoolean("profileImageNeedsAgreement", it) }
185
+ account?.nameNeedsAgreement?.let { profile.putBoolean("nameNeedsAgreement", it) }
186
+ account?.ciNeedsAgreement?.let { profile.putBoolean("ciNeedsAgreement", it) }
187
+ promise.resolve(profile)
188
+ }
189
+ }
190
+
191
+ // 배송지 조회
192
+ @ReactMethod
193
+ override fun shippingAddresses(promise: Promise) {
194
+ UserApiClient.instance.shippingAddresses { addresses, error ->
195
+ if (error != null) {
196
+ promise.reject("E_FAILED_OPERATION", error.message, error)
197
+ return@shippingAddresses
198
+ }
199
+
200
+ if (addresses == null) {
201
+ promise.reject("E_SHIPPING_ADDRESSES_NOT_FOUND", "Shipping addresses not found")
202
+ return@shippingAddresses
203
+ }
204
+
205
+ val result = Arguments.createMap()
206
+ result.putString("userId", addresses.userId?.toString())
207
+ addresses.needsAgreement?.let { result.putBoolean("needsAgreement", it) }
208
+
209
+ val array = Arguments.createArray()
210
+ addresses.shippingAddresses?.map { addr ->
211
+ Arguments.createMap().apply {
212
+ putString("id", addr.id?.toString())
213
+ putString("name", addr.name)
214
+ addr.isDefault?.let { putBoolean("isDefault", it) }
215
+ putString("updatedAt", formatDate(addr.updatedAt))
216
+ putString("type", addr.type?.toString())
217
+ putString("baseAddress", addr.baseAddress)
218
+ putString("detailAddress", addr.detailAddress)
219
+ putString("receiverName", addr.receiverName)
220
+ putString("receiverPhoneNumber1", addr.receiverPhoneNumber1)
221
+ putString("receiverPhoneNumber2", addr.receiverPhoneNumber2)
222
+ putString("zoneNumber", addr.zoneNumber)
223
+ putString("zipCode", addr.zipCode)
224
+ }
225
+ }?.forEach(array::pushMap)
226
+ result.putArray("shippingAddresses", array)
227
+
228
+ promise.resolve(result)
229
+ }
230
+ }
231
+
232
+ // 서비스 약관 조회
233
+ @ReactMethod
234
+ override fun serviceTerms(promise: Promise) {
235
+ UserApiClient.instance.serviceTerms { terms, error ->
236
+ if (error != null) {
237
+ promise.reject("E_FAILED_OPERATION", error.message, error)
238
+ return@serviceTerms
239
+ }
240
+
241
+ val result = Arguments.createMap()
242
+ terms?.id?.let { result.putString("userId", it.toString()) }
243
+
244
+ val array = Arguments.createArray()
245
+ terms?.serviceTerms?.map { term ->
246
+ Arguments.createMap().apply {
247
+ putString("tag", term.tag)
248
+ putBoolean("agreed", term.agreed)
249
+ putBoolean("required", term.required)
250
+ putBoolean("revocable", term.revocable)
251
+ term.agreedAt?.let { putString("agreedAt", formatDate(it)) }
252
+ }
253
+ }?.forEach(array::pushMap)
254
+ if (array.size() > 0) {
255
+ result.putArray("serviceTerms", array)
256
+ }
257
+
258
+ promise.resolve(result)
259
+ }
260
+ }
261
+
262
+ // 카카오계정 웹 로그인
263
+ private fun loginWithAccount(promise: Promise) {
264
+ val activity = currentActivity
265
+
266
+ if (activity == null) {
267
+ promise.reject("E_ACTIVITY_DOES_NOT_EXIST", "Activity doesn't exist")
268
+ return
269
+ }
270
+
271
+ UserApiClient.instance.loginWithKakaoAccount(activity) { token, error ->
272
+ when {
273
+ token != null -> promise.resolve(resolveToken(token.accessToken, token.refreshToken, token.idToken, token.scopes))
274
+ error != null -> promise.reject(resolveErrorCode(error), error.message, error)
275
+ else -> promise.reject("E_UNKNOWN_ERROR", "Login failed")
276
+ }
277
+ }
278
+ }
279
+
280
+ // 앱 메타데이터 조회
281
+ private fun resolveMetaData(key: String): String? {
282
+ return try {
283
+ val packageInfo = reactApplicationContext.packageManager.getApplicationInfo(
284
+ reactApplicationContext.packageName,
285
+ PackageManager.GET_META_DATA
286
+ )
287
+
288
+ packageInfo.metaData?.getString(key)
289
+ } catch (_: Exception) {
290
+ null
291
+ }
292
+ }
293
+
294
+ // 문자열 리소스 조회
295
+ private fun resolveString(name: String): String? {
296
+ val resourceId = reactApplicationContext.resources.getIdentifier(
297
+ name,
298
+ "string",
299
+ reactApplicationContext.packageName
300
+ )
301
+
302
+ if (resourceId == 0) {
303
+ return null
304
+ }
305
+
306
+ return reactApplicationContext.getString(resourceId)
307
+ }
308
+
309
+ // 토큰 응답 생성
310
+ private fun resolveToken(accessToken: String?, refreshToken: String?, idToken: String? = null, scopes: List<String>? = null): WritableMap {
311
+ val token = Arguments.createMap()
312
+ val current = TokenManagerProvider.instance.manager.getToken()
313
+
314
+ token.putString("accessToken", accessToken)
315
+ token.putString("refreshToken", refreshToken)
316
+ token.putString("idToken", idToken)
317
+ token.putString("accessTokenExpiresAt", formatDate(current?.accessTokenExpiresAt))
318
+ token.putString("refreshTokenExpiresAt", formatDate(current?.refreshTokenExpiresAt))
319
+ token.putString("appKeyHash", Utility.getKeyHash(reactApplicationContext))
320
+
321
+ val scopeArray = Arguments.createArray()
322
+ scopes?.forEach { scopeArray.pushString(it) }
323
+ token.putArray("scopes", scopeArray)
324
+
325
+ return token
326
+ }
327
+
328
+ // 에러 코드 변환
329
+ private fun resolveErrorCode(error: Throwable): String {
330
+ return when {
331
+ error is ClientError && error.reason == ClientErrorCause.Cancelled ->
332
+ "E_CANCELLED_OPERATION"
333
+ else -> "E_FAILED_OPERATION"
334
+ }
335
+ }
336
+
337
+ // 날짜 포맷 변환
338
+ private fun formatDate(date: Date?): String? {
339
+ if (date == null) {
340
+ return null
341
+ }
342
+
343
+ val formatter = SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", Locale.US)
344
+ formatter.timeZone = TimeZone.getTimeZone("UTC")
345
+ return formatter.format(date)
346
+ }
347
+ }
@@ -0,0 +1,46 @@
1
+ package com.packagekr.kakao
2
+
3
+ import com.facebook.react.BaseReactPackage
4
+ import com.facebook.react.bridge.NativeModule
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.module.annotations.ReactModule
7
+ import com.facebook.react.module.model.ReactModuleInfo
8
+ import com.facebook.react.module.model.ReactModuleInfoProvider
9
+ import com.facebook.react.uimanager.ViewManager
10
+
11
+ class RNKakaoSigninPackage : BaseReactPackage() {
12
+ override fun getModule(name: String, reactContext: ReactApplicationContext): NativeModule? {
13
+ return when (name) {
14
+ RNKakaoSigninModule.NAME -> RNKakaoSigninModule(reactContext)
15
+ else -> null
16
+ }
17
+ }
18
+
19
+ // 모듈 정보 생성
20
+ override fun getReactModuleInfoProvider(): ReactModuleInfoProvider {
21
+ val moduleList = arrayOf(RNKakaoSigninModule::class.java)
22
+ val reactModuleInfoMap = HashMap<String, ReactModuleInfo>()
23
+
24
+ for (moduleClass in moduleList) {
25
+ val reactModule = moduleClass.getAnnotation(ReactModule::class.java) ?: continue
26
+
27
+ reactModuleInfoMap[reactModule.name] = ReactModuleInfo(
28
+ reactModule.name,
29
+ moduleClass.name,
30
+ false,
31
+ reactModule.needsEagerInit,
32
+ reactModule.isCxxModule,
33
+ true
34
+ )
35
+ }
36
+
37
+ return ReactModuleInfoProvider { reactModuleInfoMap }
38
+ }
39
+
40
+ // 뷰 매니저 반환
41
+ override fun createViewManagers(
42
+ reactContext: ReactApplicationContext
43
+ ): List<ViewManager<*, *>> {
44
+ return emptyList()
45
+ }
46
+ }
@@ -0,0 +1,100 @@
1
+ import Foundation
2
+
3
+ import KakaoSDKCommon
4
+ import KakaoSDKAuth
5
+
6
+ enum RNKakaoError {
7
+ // 로그인 에러 메시지 보정
8
+ private static func resolveAuthMessage(
9
+ _ reason: AuthFailureReason,
10
+ _ authErrorInfo: AuthErrorInfo?,
11
+ _ fallback: String
12
+ ) -> (code: String, message: String) {
13
+ let description = authErrorInfo?.errorDescription?.trimmingCharacters(in: .whitespacesAndNewlines)
14
+ let normalizedDescription = description?.lowercased() ?? ""
15
+
16
+ switch reason {
17
+ case .InvalidRequest:
18
+ if normalizedDescription.contains("bundle") {
19
+ return ("KAKAO_INVALID_BUNDLE_ID", "iOS 번들 ID 설정이 올바르지 않습니다. Kakao 콘솔의 iOS 번들 ID와 Xcode 설정을 확인해주세요.")
20
+ }
21
+ if normalizedDescription.contains("scheme") || normalizedDescription.contains("redirect") {
22
+ return ("KAKAO_INVALID_URL_SCHEME", "iOS URL scheme 설정이 올바르지 않습니다. Info.plist의 URL Types, KAKAO_APP_SCHEME, Kakao 콘솔 설정을 확인해주세요.")
23
+ }
24
+ if normalizedDescription.contains("client") || normalizedDescription.contains("app key") {
25
+ return ("KAKAO_INVALID_APP_KEY", "KAKAO_APP_KEY 값이 올바르지 않습니다. Kakao 네이티브 앱 키와 Info.plist 설정을 확인해주세요.")
26
+ }
27
+ return ("KAKAO_INVALID_REQUEST", "로그인 요청이 올바르지 않습니다. Kakao iOS 앱 설정과 전달 파라미터를 확인해주세요.")
28
+
29
+ case .InvalidClient:
30
+ return ("KAKAO_INVALID_CLIENT", "카카오 iOS 앱 설정이 올바르지 않습니다. KAKAO_APP_KEY, 번들 ID, iOS 플랫폼 등록값을 확인해주세요.")
31
+
32
+ case .AccessDenied:
33
+ return ("KAKAO_ACCESS_DENIED", "사용자가 카카오 로그인을 취소했거나 접근 권한을 거부했습니다.")
34
+
35
+ case .InvalidScope:
36
+ return ("KAKAO_INVALID_SCOPE", "유효하지 않은 동의 항목(scope)입니다. 요청한 동의 항목과 Kakao 콘솔 설정을 확인해주세요.")
37
+
38
+ case .Misconfigured:
39
+ return ("KAKAO_MISCONFIGURED", "카카오 iOS 설정이 올바르지 않습니다. 번들 ID, URL scheme, KAKAO_APP_KEY, Kakao 콘솔 설정을 확인해주세요.")
40
+
41
+ case .Unauthorized:
42
+ return ("KAKAO_UNAUTHORIZED", "카카오 로그인 권한이 없습니다. 앱 권한과 플랫폼 설정을 확인해주세요.")
43
+
44
+ case .InvalidGrant:
45
+ return ("KAKAO_INVALID_GRANT", "인가 정보가 유효하지 않습니다. 다시 로그인해주세요.")
46
+
47
+ case .ServerError:
48
+ return ("KAKAO_SERVER_ERROR", "카카오 서버 오류가 발생했습니다. 잠시 후 다시 시도해주세요.")
49
+
50
+ default:
51
+ return ("KAKAO_AUTH_ERROR", description ?? authErrorInfo?.error.rawValue ?? fallback)
52
+ }
53
+ }
54
+
55
+ // SDK 에러 해석
56
+ static func parse(_ error: Error) -> (code: String, message: String) {
57
+ guard let sdkError = error as? SdkError else {
58
+ return ("KAKAO_ERROR", error.localizedDescription)
59
+ }
60
+
61
+ switch sdkError {
62
+ // 클라이언트 에러
63
+ case .ClientFailed(let reason, let errorMessage):
64
+ switch reason {
65
+ case .Cancelled:
66
+ return ("KAKAO_CANCELLED", "사용자가 로그인을 취소했습니다.")
67
+ case .NotSupported:
68
+ return ("KAKAO_NOT_SUPPORTED", "지원하지 않는 기능입니다.")
69
+ case .BadParameter:
70
+ return ("KAKAO_BAD_PARAMETER", "잘못된 파라미터입니다. \(errorMessage ?? "")")
71
+ case .TokenNotFound:
72
+ return ("KAKAO_TOKEN_NOT_FOUND", "로그인이 필요합니다.")
73
+ case .IllegalState:
74
+ return ("KAKAO_ILLEGAL_STATE", "잘못된 상태입니다. \(errorMessage ?? "")")
75
+ default:
76
+ return ("KAKAO_CLIENT_ERROR", errorMessage ?? error.localizedDescription)
77
+ }
78
+
79
+ // API 에러
80
+ case .ApiFailed(let reason, let errorInfo):
81
+ switch reason {
82
+ case .InvalidAccessToken:
83
+ return ("KAKAO_UNAUTHORIZED", "인증이 만료되었습니다. 다시 로그인해주세요.")
84
+ case .Permission, .InsufficientScope:
85
+ return ("KAKAO_FORBIDDEN", "권한이 없습니다. 동의 항목을 확인해주세요.")
86
+ case .ApiLimitExceed:
87
+ return ("KAKAO_RATE_LIMIT", "요청이 너무 많습니다. 잠시 후 다시 시도해주세요.")
88
+ default:
89
+ return ("KAKAO_API_ERROR", errorInfo?.msg ?? error.localizedDescription)
90
+ }
91
+
92
+ // 인증 에러
93
+ case .AuthFailed(let reason, let authErrorInfo):
94
+ return resolveAuthMessage(reason, authErrorInfo, error.localizedDescription)
95
+
96
+ default:
97
+ return ("KAKAO_ERROR", error.localizedDescription)
98
+ }
99
+ }
100
+ }
@@ -0,0 +1 @@
1
+ #import <React/RCTBridgeModule.h>
@@ -0,0 +1,8 @@
1
+ @class RNKakaoSignin;
2
+
3
+ @interface RNKakaoSignin : NSObject
4
+ - (RNKakaoSignin *)returnSwiftClassInstance;
5
+ + (BOOL)isKakaoTalkLoginUrl:(NSURL *)url;
6
+ + (BOOL)handleOpenUrl:(NSURL *)url;
7
+ @end
8
+
@@ -0,0 +1,13 @@
1
+ #import <React/RCTBridgeModule.h>
2
+ #import <RNKakaoSigninSpec/RNKakaoSigninSpec.h>
3
+
4
+ @interface RCT_EXTERN_MODULE(RNKakaoSignin, NSObject)
5
+
6
+ RCT_EXTERN_METHOD(login:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
7
+ RCT_EXTERN_METHOD(loginWithKakaoAccount:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
8
+ RCT_EXTERN_METHOD(logout:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
9
+ RCT_EXTERN_METHOD(unlink:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
10
+ RCT_EXTERN_METHOD(getProfile:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
11
+ RCT_EXTERN_METHOD(getAccessToken:(RCTPromiseResolveBlock *)resolve rejecter:(RCTPromiseRejectBlock *)reject);
12
+
13
+ @end