@pyrocancode/react-native-vk-auth 0.4.1 → 1.0.0

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.
package/ios/Event.swift CHANGED
@@ -1,7 +1,6 @@
1
1
  import Foundation
2
2
  import OSLog
3
-
4
- @_implementationOnly import VKSDK
3
+ import VKID
5
4
 
6
5
  extension VkAuth {
7
6
  func send(event: Event) {
@@ -25,17 +24,11 @@ struct Event {
25
24
  self.event = event
26
25
  }
27
26
 
28
- // MARK: - Accessors
29
-
30
27
  static let onLogout = Self(OnLogout())
31
28
 
32
- static func onAuth(userSession: VKID.UserSession) -> Self {
29
+ static func onAuth(userSession: UserSession) -> Self {
33
30
  .init(OnAuth(userSession: userSession))
34
31
  }
35
-
36
- static func onSilentDataReceive(silentToken: VKID.SilentToken) -> Self {
37
- .init(OnSilentDataReceive(silentToken: silentToken))
38
- }
39
32
  }
40
33
 
41
34
  extension Event: CustomStringConvertible {
@@ -54,17 +47,8 @@ extension Event {
54
47
  let name = "onAuth"
55
48
  let body: Any
56
49
 
57
- init(userSession: VKID.UserSession) {
50
+ init(userSession: UserSession) {
58
51
  self.body = userSession.dictionary
59
52
  }
60
53
  }
61
-
62
- private struct OnSilentDataReceive: RCTEvent {
63
- let name = "onSilentDataReceive"
64
- let body: Any
65
-
66
- init(silentToken: VKID.SilentToken) {
67
- self.body = ["token": ["value": silentToken.token.value], "uuid": silentToken.uuid]
68
- }
69
- }
70
54
  }
@@ -1,26 +1,30 @@
1
1
  import Foundation
2
-
3
- @_implementationOnly import VKSDK
2
+ import VKID
4
3
 
5
4
  protocol RCTDomain {
6
5
  var dictionary: [String: Any?] { get }
7
6
  }
8
7
 
9
- extension VKID.Profile: RCTDomain {
10
- #warning("Use value instead of description for userID")
11
- var dictionary: [String : Any?] {
8
+ extension User: RCTDomain {
9
+ var dictionary: [String: Any?] {
12
10
  [
13
- "userID": ["value": self.id.description],
14
- "firstName": self.name?.firstName,
15
- "lastName": self.name?.lastName,
16
- "phone": self.phoneMask,
17
- "photo200": self.image?.url?.absoluteString
11
+ "userID": ["value": String(self.id.value)],
12
+ "firstName": self.firstName,
13
+ "lastName": self.lastName,
14
+ "phone": self.phone,
15
+ "photo200": self.avatarURL?.absoluteString,
16
+ "email": self.email,
17
+ "userHash": nil,
18
18
  ]
19
19
  }
20
20
  }
21
21
 
22
- extension VKID.UserSession: RCTDomain {
23
- var dictionary: [String : Any?] {
24
- ["type": self.authorized == nil ? "authenticated" : "authorized"]
22
+ extension UserSession {
23
+ var dictionary: [String: Any?] {
24
+ [
25
+ "type": "authorized",
26
+ "userId": String(self.userId.value),
27
+ "accessToken": self.accessToken.value,
28
+ ]
25
29
  }
26
30
  }
package/ios/VkAuth.swift CHANGED
@@ -1,22 +1,40 @@
1
1
  import UIKit
2
2
  import OSLog
3
+ import React
4
+ import VKID
5
+ import VKIDCore
6
+
7
+ // MARK: - Общие хелперы (VK ID SDK 2.x, OAuth 2.1)
8
+
9
+ fileprivate func vkAuthTopViewController() -> UIViewController? {
10
+ let keyWindow: UIWindow?
11
+ if #available(iOS 13.0, *) {
12
+ keyWindow = UIApplication.shared.connectedScenes
13
+ .compactMap { $0 as? UIWindowScene }
14
+ .flatMap(\.windows)
15
+ .first { $0.isKeyWindow }
16
+ } else {
17
+ keyWindow = UIApplication.shared.keyWindow
18
+ }
19
+ guard var top = keyWindow?.rootViewController else { return nil }
20
+ while let presented = top.presentedViewController {
21
+ top = presented
22
+ }
23
+ return top
24
+ }
3
25
 
4
- @_implementationOnly import VKSDK
26
+ /// Публичный клиент + PKCE внутри SDK. Для обмена кода на бэкенде позже можно сменить на `confidentialClientFlow`.
27
+ fileprivate func vkAuthMakeConfiguration() -> AuthConfiguration {
28
+ AuthConfiguration(
29
+ flow: .publicClientFlow(),
30
+ scope: Scope([])
31
+ )
32
+ }
5
33
 
34
+ /// React Native мост для VK ID SDK. См. https://id.vk.com/about/business/go/docs/ru/vkid/latest/vk-id/connection/migration/ios/migration-ios
6
35
  @objc(VkAuth)
7
36
  final class VkAuth: RCTEventEmitter {
8
- private static var _sharedSDK: VKSDK.VK.Type2<App, VKID>? // DO NOT USE THIS DIRECTLY
9
- fileprivate static var _sharedSuperappKit: VkAuth?
10
-
11
- fileprivate static var sharedSDK: VKSDK.VK.Type2<App, VKID> {
12
- guard let _shared = Self._sharedSDK else {
13
- fatalError("VKSDK is not initialized. Call initialize(_:vkid:) method before using VkAuth.")
14
- }
15
-
16
- return _shared
17
- }
18
-
19
- private var activeAuthCompletion: ((Result<VKSDK.VKID.AccessToken, Error>) -> Void)?
37
+ fileprivate static weak var _sharedEmitter: VkAuth?
20
38
 
21
39
  @objc(initialize:vkid:)
22
40
  func initialize(_ app: NSDictionary, vkid: NSDictionary) {
@@ -30,50 +48,50 @@ final class VkAuth: RCTEventEmitter {
30
48
  }
31
49
 
32
50
  do {
33
- Self._sharedSDK = try VK {
34
- App(credentials: .init(clientId: clientId, clientSecret: clientSecret))
35
- VKID()
36
- }
37
- Self._sharedSuperappKit = self
51
+ try VKID.shared.set(
52
+ config: Configuration(
53
+ appCredentials: AppCredentials(
54
+ clientId: clientId,
55
+ clientSecret: clientSecret
56
+ )
57
+ )
58
+ )
59
+ VkAuth._sharedEmitter = self
60
+ VKID.shared.add(observer: self)
38
61
  } catch {
39
- os_log("VKSDK initialization failed", type: .error, error.localizedDescription)
62
+ os_log("VKID initialization failed: %{public}@", type: .error, error.localizedDescription)
40
63
  }
41
64
  }
42
65
 
43
66
  @objc(openURL:)
44
- func openURL(_ url: String) {
45
- guard let url = URL(string: url) else {
46
- return
47
- }
48
-
49
- try? Self.sharedSDK.open(url: url)
67
+ func openURL(_ urlString: String) {
68
+ guard let url = URL(string: urlString) else { return }
69
+ _ = VKID.shared.open(url: url)
50
70
  }
51
71
 
52
- // MARK: - Auth
53
-
54
72
  @objc func startAuth() {
55
- let flow = VKID.AuthFlow.exchanging(tokenExchanger: .custom(weak: self))
56
- let authController = VKID.AuthController(flow: flow, delegate: self)
57
-
58
- let viewController = try! Self.sharedSDK.vkid.ui(for: authController).uiViewController()
59
- UIApplication.shared.keyWindow?.rootViewController?.present(viewController, animated: true)
73
+ guard let presenter = vkAuthTopViewController() else {
74
+ os_log("No presenter for VKID authorize", type: .error)
75
+ return
76
+ }
77
+ VKID.shared.authorize(
78
+ with: vkAuthMakeConfiguration(),
79
+ using: .uiViewController(presenter)
80
+ ) { _ in }
60
81
  }
61
82
 
62
83
  @objc func closeAuth() {
63
- UIApplication.shared.keyWindow?.rootViewController?.dismiss(animated: true)
64
- os_log("Authorization closed", type: .info)
84
+ vkAuthTopViewController()?.dismiss(animated: true)
85
+ os_log("Authorization UI dismissed", type: .info)
65
86
  }
66
87
 
67
88
  @objc func logout() {
68
- guard let userSession = Self.sharedSDK.vkid.userSessions.first else {
69
- return
70
- }
71
-
72
- userSession.authorized?.logout { [weak self] _ in
73
- self?.send(event: .onLogout)
89
+ guard let session = VKID.shared.authorizedSessions.first else { return }
90
+ session.logout { [weak self] result in
91
+ if case .success = result {
92
+ self?.send(event: .onLogout)
93
+ }
74
94
  }
75
-
76
- os_log("Logout user session", type: .info, "\(userSession)")
77
95
  }
78
96
 
79
97
  @objc(getUserSessions:rejecter:)
@@ -81,7 +99,7 @@ final class VkAuth: RCTEventEmitter {
81
99
  resolver resolve: RCTPromiseResolveBlock,
82
100
  rejecter reject: RCTPromiseRejectBlock
83
101
  ) {
84
- resolve(Self.sharedSDK.vkid.userSessions.map(\.dictionary))
102
+ resolve(VKID.shared.authorizedSessions.map(\.dictionary))
85
103
  }
86
104
 
87
105
  @objc(getUserProfile:rejecter:)
@@ -89,92 +107,90 @@ final class VkAuth: RCTEventEmitter {
89
107
  resolver resolve: @escaping RCTPromiseResolveBlock,
90
108
  rejecter reject: @escaping RCTPromiseRejectBlock
91
109
  ) {
92
- guard let authorized = Self.sharedSDK.vkid.userSessions.first?.authorized else {
93
- reject(nil, nil, nil)
110
+ guard let session = VKID.shared.authorizedSessions.first else {
111
+ reject("no_session", "No authorized VK ID session", nil)
94
112
  return
95
113
  }
96
-
97
- authorized.requestProfile { result in
98
- do {
99
- let profile = try result.get()
100
- resolve(profile.dictionary)
101
- } catch {
102
- reject(nil, nil, nil)
114
+ session.fetchUser { result in
115
+ switch result {
116
+ case .success:
117
+ if let user = session.user {
118
+ resolve(user.dictionary)
119
+ } else {
120
+ resolve(["userID": ["value": String(session.userId.value)]])
121
+ }
122
+ case .failure(let error):
123
+ reject("profile_failed", error.localizedDescription, error)
103
124
  }
104
125
  }
105
126
  }
106
- }
107
-
108
- extension VkAuth: TokenExchanging {
109
- func exchange(silentToken: VKSDK.VKID.SilentToken, completion: @escaping (Result<VKSDK.VKID.AccessToken, Error>) -> Void) {
110
- self.activeAuthCompletion = completion
111
- self.send(event: .onSilentDataReceive(silentToken: silentToken))
112
- }
113
127
 
114
128
  @objc(accessTokenChangedSuccess:userId:)
115
129
  func accessTokenChangedSuccess(_ token: String, userId: NSNumber) {
116
- let accessToken = VKID.AccessToken(.init(token), userID: .init(userId.uint64Value))
117
- self.activeAuthCompletion?(.success(accessToken))
118
- self.activeAuthCompletion = nil
119
-
120
- os_log("Token exchange succeeded", type: .info)
130
+ os_log("accessTokenChangedSuccess ignored on VK ID iOS (no silent exchange)", type: .info)
121
131
  }
122
132
 
123
133
  @objc(accessTokenChangedFailed:)
124
134
  func accessTokenChangedFailed(_ error: NSDictionary) {
125
- let reactError = NSError(domain: "React Native", code: -9999, userInfo: error as! [String : Any])
126
- self.activeAuthCompletion?(.failure(reactError))
127
- self.activeAuthCompletion = nil
135
+ os_log("accessTokenChangedFailed ignored on VK ID iOS", type: .info)
136
+ }
128
137
 
129
- os_log("Token exchange failed", type: .error, reactError.localizedDescription)
138
+ @objc(supportedEvents)
139
+ override func supportedEvents() -> [String]! {
140
+ ["onLogout", "onAuth"]
130
141
  }
131
142
  }
132
143
 
133
- extension VkAuth: VKIDFlowDelegate {
134
- func vkid(_ vkid: VKSDK.VKID.Module, didCompleteAuthWith result: Result<VKSDK.VKID.UserSession, Error>) {
144
+ extension VkAuth: VKIDObserver {
145
+ func vkid(_ vkid: VKID, didCompleteAuthWith result: AuthResult, in oAuth: OAuthProvider) {
135
146
  do {
136
- self.send(event: .onAuth(userSession: try result.get()))
147
+ let session = try result.get()
148
+ send(event: .onAuth(userSession: session))
149
+ } catch AuthError.cancelled {
150
+ os_log("VKID auth cancelled", type: .info)
137
151
  } catch {
138
- os_log("Authorization failed", type: .error, error.localizedDescription)
152
+ os_log("VKID auth failed: %{public}@", type: .error, error.localizedDescription)
139
153
  }
140
154
  }
155
+
156
+ func vkid(_ vkid: VKID, didLogoutFrom session: UserSession, with result: LogoutResult) {
157
+ if case .success = result {
158
+ send(event: .onLogout)
159
+ }
160
+ }
161
+
162
+ func vkid(_ vkid: VKID, didStartAuthUsing oAuth: OAuthProvider) {}
163
+
164
+ func vkid(_ vkid: VKID, didUpdateUserIn session: UserSession, with result: UserFetchingResult) {}
165
+
166
+ func vkid(_ vkid: VKID, didRefreshAccessTokenIn session: UserSession, with result: TokenRefreshingResult) {}
141
167
  }
142
168
 
143
169
  @objc(RTCVkOneTapButton)
144
170
  final class OneTapButtonManager: RCTViewManager {
145
171
  override func view() -> UIView! {
146
- guard let sharedSuperappKit = VkAuth._sharedSuperappKit else {
147
- fatalError("VkAuth is not initialized. Call initialize(_:vkid:) method before using VkAuth.")
172
+ guard VkAuth._sharedEmitter != nil else {
173
+ os_log("VkAuth not initialized before OneTap", type: .fault)
148
174
  return UIView()
149
175
  }
150
- var authPresenter: VKSDK.UIKitPresenter = .newUIWindow
151
- if let root = UIApplication.shared.keyWindow?.rootViewController {
152
- authPresenter = .uiViewController(root)
176
+ guard let root = vkAuthTopViewController() else {
177
+ return UIView()
153
178
  }
154
179
 
155
- let flow = VKID.AuthFlow.exchanging(tokenExchanger: .custom(weak: sharedSuperappKit))
156
- let authController = VKID.AuthController(flow: flow, delegate: sharedSuperappKit)
157
-
158
- let button = VKID.OneTapButton(
159
- mode: .default,
160
- controllerConfiguration: .authController(
161
- authController,
162
- presenter: authPresenter
163
- )
180
+ let button = OneTapButton(
181
+ layout: .regular(
182
+ height: .medium(.h44),
183
+ cornerRadius: 8
184
+ ),
185
+ presenter: .uiViewController(root),
186
+ authConfiguration: vkAuthMakeConfiguration(),
187
+ onCompleteAuth: nil
164
188
  )
165
189
 
166
- guard let buttonView = try? VkAuth.sharedSDK.vkid.ui(for: button).uiView() else {
167
- fatalError("OneTapButton configuration problem")
190
+ guard let view = try? VKID.shared.ui(for: button).uiView() else {
191
+ os_log("OneTapButton uiView failed", type: .error)
168
192
  return UIView()
169
193
  }
170
-
171
- return buttonView
172
- }
173
- }
174
-
175
- extension VkAuth {
176
- @objc(supportedEvents)
177
- override func supportedEvents() -> [String] {
178
- ["onLogout", "onAuth", "onSilentDataReceive"]
194
+ return view
179
195
  }
180
196
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pyrocancode/react-native-vk-auth",
3
- "version": "0.4.1",
4
- "description": "React Native VK ID Auth (fork of @devsomersets/react-native-vk-auth)",
3
+ "version": "1.0.0",
4
+ "description": "Тонкая обёртка над VK ID SDK для React Native: OAuth 2.1, нативные модули iOS и Android.",
5
5
  "main": "src/index.tsx",
6
6
  "module": "src/index.tsx",
7
7
  "types": "src/index.tsx",
@@ -10,26 +10,33 @@ Pod::Spec.new do |s|
10
10
  s.homepage = package["homepage"]
11
11
  s.license = package["license"]
12
12
  s.authors = package["author"]
13
- s.platforms = { :ios => "11.4" }
13
+ s.platforms = { :ios => "15.1" }
14
14
  s.source = { :git => "https://github.com/pyrocancode/react-native-vk-auth.git", :tag => "#{s.version}" }
15
15
 
16
16
  s.source_files = "ios/**/*.{h,m,mm,swift}"
17
17
 
18
- s.dependency "React-Core"
19
- s.dependency "VK-SDK"
18
+ # VK ID SDK (OAuth 2.1). См. https://id.vk.com/about/business/go/docs/ru/vkid/latest/vk-id/connection/migration/ios/migration-ios
19
+ s.dependency "VKID", "2.9.2"
20
20
 
21
- # Don't install the dependencies when we run `pod install` in the old architecture.
22
21
  if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
23
22
  s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
24
- s.pod_target_xcconfig = {
23
+ s.pod_target_xcconfig = {
25
24
  "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
26
25
  "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
27
26
  "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
28
27
  }
29
- s.dependency "React-Codegen"
30
- s.dependency "RCT-Folly"
31
- s.dependency "RCTRequired"
32
- s.dependency "RCTTypeSafety"
33
- s.dependency "ReactCommon/turbomodule/core"
28
+
29
+ unless respond_to?(:install_modules_dependencies, true)
30
+ rn_pods = File.expand_path(File.join(__dir__, '..', '..', 'react-native', 'scripts', 'react_native_pods.rb'))
31
+ require rn_pods if File.exist?(rn_pods)
32
+ end
33
+
34
+ if respond_to?(:install_modules_dependencies, true)
35
+ install_modules_dependencies(s)
36
+ else
37
+ raise "[@pyrocancode/react-native-vk-auth] New Architecture requires React Native scripts (install_modules_dependencies). Check that react-native is in node_modules."
38
+ end
39
+ else
40
+ s.dependency "React-Core"
34
41
  end
35
42
  end