@thelacanians/vue-native-cli 0.4.2 → 0.4.4
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/dist/cli.js +43 -23
- package/native/android/README.md +205 -0
- package/native/android/VueNativeCore/build.gradle.kts +100 -0
- package/native/android/VueNativeCore/consumer-rules.pro +12 -0
- package/native/android/VueNativeCore/proguard-rules.pro +33 -0
- package/native/android/VueNativeCore/src/main/AndroidManifest.xml +17 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/ErrorOverlayView.kt +94 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/HotReloadManager.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSPolyfills.kt +652 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/JSRuntime.kt +207 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Bridge/NativeBridge.kt +417 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/ComponentRegistry.kt +76 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActionSheetFactory.kt +78 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VActivityIndicatorFactory.kt +46 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VAlertDialogFactory.kt +84 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VButtonFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VCheckboxFactory.kt +93 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VDropdownFactory.kt +125 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VImageFactory.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VInputFactory.kt +210 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VKeyboardAvoidingFactory.kt +31 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VListFactory.kt +183 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VModalFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPickerFactory.kt +57 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VPressableFactory.kt +109 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VProgressBarFactory.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRadioFactory.kt +103 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRefreshControlFactory.kt +73 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VRootFactory.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSafeAreaFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VScrollViewFactory.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSectionListFactory.kt +144 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSegmentedControlFactory.kt +77 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSliderFactory.kt +74 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VStatusBarFactory.kt +52 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VSwitchFactory.kt +62 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VTextFactory.kt +53 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VVideoFactory.kt +191 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VViewFactory.kt +48 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/Factories/VWebViewFactory.kt +90 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/NativeComponentFactory.kt +40 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Components/VTextNodeView.kt +23 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/GestureHelper.kt +16 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Helpers/TouchableView.kt +105 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AnimationModule.kt +292 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AppStateModule.kt +41 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AsyncStorageModule.kt +59 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/AudioModule.kt +331 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BackgroundTaskModule.kt +166 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BiometryModule.kt +56 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/BluetoothModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CalendarModule.kt +198 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/CameraModule.kt +64 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ClipboardModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ContactsModule.kt +288 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DatabaseModule.kt +229 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/DeviceInfoModule.kt +39 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/FileSystemModule.kt +193 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/GeolocationModule.kt +68 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HapticsModule.kt +61 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/HttpModule.kt +111 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/IAPModule.kt +302 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/KeyboardModule.kt +26 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/LinkingModule.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModule.kt +27 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NativeModuleRegistry.kt +92 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NetworkModule.kt +75 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/NotificationsModule.kt +181 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/OTAModule.kt +255 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PerformanceModule.kt +147 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/PermissionsModule.kt +126 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SecureStorageModule.kt +51 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SensorsModule.kt +134 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/ShareModule.kt +36 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/SocialAuthModule.kt +160 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Modules/WebSocketModule.kt +155 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Styling/StyleEngine.kt +802 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/Tags.kt +43 -0
- package/native/android/VueNativeCore/src/main/kotlin/com/vuenative/core/VueNativeActivity.kt +169 -0
- package/native/android/VueNativeCore/src/main/res/values/ids.xml +8 -0
- package/native/android/app/build.gradle.kts +45 -0
- package/native/android/app/proguard-rules.pro +5 -0
- package/native/android/app/src/main/AndroidManifest.xml +25 -0
- package/native/android/app/src/main/assets/.gitkeep +0 -0
- package/native/android/app/src/main/kotlin/com/vuenative/example/counter/MainActivity.kt +14 -0
- package/native/android/app/src/main/res/layout/activity_main.xml +6 -0
- package/native/android/app/src/main/res/values/strings.xml +3 -0
- package/native/android/app/src/main/res/values/themes.xml +9 -0
- package/native/android/app/src/main/res/xml/network_security_config.xml +8 -0
- package/native/android/build.gradle.kts +6 -0
- package/native/android/gradle/wrapper/gradle-wrapper.jar +0 -0
- package/native/android/gradle/wrapper/gradle-wrapper.properties +7 -0
- package/native/android/gradle.properties +4 -0
- package/native/android/gradlew +87 -0
- package/native/android/gradlew.bat +48 -0
- package/native/android/settings.gradle.kts +20 -0
- package/native/ios/VueNativeCore/Package.resolved +23 -0
- package/native/ios/VueNativeCore/Package.swift +32 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/CertificatePinning.swift +132 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/ErrorOverlayView.swift +92 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/HotReloadManager.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSPolyfills.swift +711 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/JSRuntime.swift +421 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/NativeBridge.swift +891 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Bridge/VueNativeViewController.swift +88 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/ComponentRegistry.swift +193 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActionSheetFactory.swift +91 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VActivityIndicatorFactory.swift +74 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VAlertDialogFactory.swift +150 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VButtonFactory.swift +93 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VCheckboxFactory.swift +114 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VDropdownFactory.swift +112 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VImageFactory.swift +172 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VInputFactory.swift +357 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VKeyboardAvoidingFactory.swift +99 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VListFactory.swift +250 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VModalFactory.swift +112 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPickerFactory.swift +96 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VPressableFactory.swift +168 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VProgressBarFactory.swift +39 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRadioFactory.swift +167 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VRefreshControlFactory.swift +153 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSafeAreaFactory.swift +56 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VScrollViewFactory.swift +240 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSectionListFactory.swift +248 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSegmentedControlFactory.swift +73 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSliderFactory.swift +63 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VStatusBarFactory.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VSwitchFactory.swift +108 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VTextFactory.swift +290 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VVideoFactory.swift +246 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VViewFactory.swift +157 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/Factories/VWebViewFactory.swift +172 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Components/NativeComponentFactory.swift +53 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/GestureWrapper.swift +107 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/TouchableView.swift +136 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Helpers/UIColor+Hex.swift +80 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AnimationModule.swift +291 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AppStateModule.swift +65 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AsyncStorageModule.swift +68 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/AudioModule.swift +366 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BackgroundTaskModule.swift +135 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BiometryModule.swift +61 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/BluetoothModule.swift +387 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CalendarModule.swift +161 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/CameraModule.swift +318 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ClipboardModule.swift +33 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ContactsModule.swift +173 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DatabaseModule.swift +259 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/DeviceInfoModule.swift +34 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/FileSystemModule.swift +233 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/GeolocationModule.swift +147 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/HapticsModule.swift +50 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/IAPModule.swift +194 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/KeyboardModule.swift +31 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/LinkingModule.swift +42 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModule.swift +28 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NativeModuleRegistry.swift +78 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NetworkModule.swift +62 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/NotificationsModule.swift +215 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/OTAModule.swift +281 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PerformanceModule.swift +138 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/PermissionsModule.swift +190 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SecureStorageModule.swift +118 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SensorsModule.swift +103 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/ShareModule.swift +49 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/SocialAuthModule.swift +240 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Modules/WebSocketModule.swift +213 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Resources/vue-native-placeholder.js +8 -0
- package/native/ios/VueNativeCore/Sources/VueNativeCore/Styling/StyleEngine.swift +885 -0
- package/native/ios/VueNativeCore/Tests/VueNativeCoreTests/JSRuntimeTests.swift +362 -0
- package/package.json +3 -2
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import UIKit
|
|
3
|
+
import AuthenticationServices
|
|
4
|
+
|
|
5
|
+
/// Native module for social authentication (Apple Sign In, Google Sign In).
|
|
6
|
+
///
|
|
7
|
+
/// Methods:
|
|
8
|
+
/// - signInWithApple() -- present Apple Sign In sheet
|
|
9
|
+
/// - signInWithGoogle(clientId: String) -- present Google OAuth web flow
|
|
10
|
+
/// - signOut(provider: String) -- clear cached credentials
|
|
11
|
+
/// - getCurrentUser(provider: String) -- check for existing session
|
|
12
|
+
///
|
|
13
|
+
/// Events:
|
|
14
|
+
/// - auth:appleCredentialRevoked -- fired when Apple credential is revoked
|
|
15
|
+
final class SocialAuthModule: NSObject, NativeModule, ASAuthorizationControllerDelegate, ASAuthorizationControllerPresentationContextProviding {
|
|
16
|
+
let moduleName = "SocialAuth"
|
|
17
|
+
private weak var bridge: NativeBridge?
|
|
18
|
+
private var appleSignInCallback: ((Any?, String?) -> Void)?
|
|
19
|
+
private var credentialObserver: NSObjectProtocol?
|
|
20
|
+
|
|
21
|
+
init(bridge: NativeBridge? = nil) {
|
|
22
|
+
self.bridge = bridge
|
|
23
|
+
super.init()
|
|
24
|
+
observeAppleCredentialRevocation()
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
28
|
+
switch method {
|
|
29
|
+
case "signInWithApple":
|
|
30
|
+
handleAppleSignIn(callback: callback)
|
|
31
|
+
|
|
32
|
+
case "signInWithGoogle":
|
|
33
|
+
guard let clientId = args.first as? String else {
|
|
34
|
+
callback(nil, "signInWithGoogle: expected clientId string")
|
|
35
|
+
return
|
|
36
|
+
}
|
|
37
|
+
handleGoogleSignIn(clientId: clientId, callback: callback)
|
|
38
|
+
|
|
39
|
+
case "signOut":
|
|
40
|
+
let provider = args.first as? String ?? "apple"
|
|
41
|
+
handleSignOut(provider: provider, callback: callback)
|
|
42
|
+
|
|
43
|
+
case "getCurrentUser":
|
|
44
|
+
let provider = args.first as? String ?? "apple"
|
|
45
|
+
handleGetCurrentUser(provider: provider, callback: callback)
|
|
46
|
+
|
|
47
|
+
default:
|
|
48
|
+
callback(nil, "SocialAuthModule: unknown method '\(method)'")
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// MARK: - Apple Sign In
|
|
53
|
+
|
|
54
|
+
private func handleAppleSignIn(callback: @escaping (Any?, String?) -> Void) {
|
|
55
|
+
appleSignInCallback = callback
|
|
56
|
+
|
|
57
|
+
let request = ASAuthorizationAppleIDProvider().createRequest()
|
|
58
|
+
request.requestedScopes = [.fullName, .email]
|
|
59
|
+
|
|
60
|
+
let controller = ASAuthorizationController(authorizationRequests: [request])
|
|
61
|
+
controller.delegate = self
|
|
62
|
+
controller.presentationContextProvider = self
|
|
63
|
+
controller.performRequests()
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ASAuthorizationControllerDelegate
|
|
67
|
+
func authorizationController(controller: ASAuthorizationController, didCompleteWithAuthorization authorization: ASAuthorization) {
|
|
68
|
+
guard let credential = authorization.credential as? ASAuthorizationAppleIDCredential else {
|
|
69
|
+
appleSignInCallback?(nil, "signInWithApple: unexpected credential type")
|
|
70
|
+
appleSignInCallback = nil
|
|
71
|
+
return
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
var result: [String: Any] = [
|
|
75
|
+
"userId": credential.user,
|
|
76
|
+
]
|
|
77
|
+
|
|
78
|
+
if let email = credential.email {
|
|
79
|
+
result["email"] = email
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
if let fullName = credential.fullName {
|
|
83
|
+
let name = [fullName.givenName, fullName.familyName]
|
|
84
|
+
.compactMap { $0 }
|
|
85
|
+
.joined(separator: " ")
|
|
86
|
+
if !name.isEmpty {
|
|
87
|
+
result["fullName"] = name
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if let tokenData = credential.identityToken, let token = String(data: tokenData, encoding: .utf8) {
|
|
92
|
+
result["identityToken"] = token
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
if let codeData = credential.authorizationCode, let code = String(data: codeData, encoding: .utf8) {
|
|
96
|
+
result["authorizationCode"] = code
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Persist user ID for session check
|
|
100
|
+
UserDefaults.standard.set(credential.user, forKey: "vn_apple_userId")
|
|
101
|
+
|
|
102
|
+
appleSignInCallback?(result, nil)
|
|
103
|
+
appleSignInCallback = nil
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
func authorizationController(controller: ASAuthorizationController, didCompleteWithError error: Error) {
|
|
107
|
+
let nsError = error as NSError
|
|
108
|
+
if nsError.domain == ASAuthorizationError.errorDomain && nsError.code == ASAuthorizationError.canceled.rawValue {
|
|
109
|
+
appleSignInCallback?(nil, "signInWithApple: user cancelled")
|
|
110
|
+
} else {
|
|
111
|
+
appleSignInCallback?(nil, "signInWithApple: \(error.localizedDescription)")
|
|
112
|
+
}
|
|
113
|
+
appleSignInCallback = nil
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
func presentationAnchor(for controller: ASAuthorizationController) -> ASPresentationAnchor {
|
|
117
|
+
return UIApplication.shared.connectedScenes
|
|
118
|
+
.compactMap { $0 as? UIWindowScene }
|
|
119
|
+
.first?.windows.first { $0.isKeyWindow } ?? UIWindow()
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// MARK: - Google Sign In (URL-based OAuth)
|
|
123
|
+
|
|
124
|
+
private func handleGoogleSignIn(clientId: String, callback: @escaping (Any?, String?) -> Void) {
|
|
125
|
+
// URL-based OAuth flow using ASWebAuthenticationSession for zero dependencies
|
|
126
|
+
let redirectURI = "com.googleusercontent.apps.\(clientId.components(separatedBy: ".").first ?? clientId):/oauthredirect"
|
|
127
|
+
let scope = "openid email profile"
|
|
128
|
+
let urlString = "https://accounts.google.com/o/oauth2/v2/auth?client_id=\(clientId)&redirect_uri=\(redirectURI)&response_type=code&scope=\(scope.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed) ?? scope)"
|
|
129
|
+
|
|
130
|
+
guard let url = URL(string: urlString) else {
|
|
131
|
+
callback(nil, "signInWithGoogle: invalid OAuth URL")
|
|
132
|
+
return
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
DispatchQueue.main.async {
|
|
136
|
+
let scheme = redirectURI.components(separatedBy: ":").first
|
|
137
|
+
let session = ASWebAuthenticationSession(url: url, callbackURLScheme: scheme) { callbackURL, error in
|
|
138
|
+
if let error = error {
|
|
139
|
+
let nsError = error as NSError
|
|
140
|
+
if nsError.domain == ASWebAuthenticationSessionError.errorDomain &&
|
|
141
|
+
nsError.code == ASWebAuthenticationSessionError.canceledLogin.rawValue {
|
|
142
|
+
callback(nil, "signInWithGoogle: user cancelled")
|
|
143
|
+
} else {
|
|
144
|
+
callback(nil, "signInWithGoogle: \(error.localizedDescription)")
|
|
145
|
+
}
|
|
146
|
+
return
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
guard let callbackURL = callbackURL,
|
|
150
|
+
let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false),
|
|
151
|
+
let code = components.queryItems?.first(where: { $0.name == "code" })?.value else {
|
|
152
|
+
callback(nil, "signInWithGoogle: no authorization code received")
|
|
153
|
+
return
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
let result: [String: Any] = [
|
|
157
|
+
"userId": code, // The auth code — exchange server-side for tokens
|
|
158
|
+
"authorizationCode": code,
|
|
159
|
+
]
|
|
160
|
+
|
|
161
|
+
UserDefaults.standard.set(code, forKey: "vn_google_authCode")
|
|
162
|
+
callback(result, nil)
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
session.prefersEphemeralWebBrowserSession = false
|
|
166
|
+
|
|
167
|
+
// Find the presentation anchor
|
|
168
|
+
if let windowScene = UIApplication.shared.connectedScenes.first as? UIWindowScene,
|
|
169
|
+
let window = windowScene.windows.first {
|
|
170
|
+
session.presentationContextProvider = window.rootViewController as? ASWebAuthenticationPresentationContextProviding
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
session.start()
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// MARK: - Sign Out
|
|
178
|
+
|
|
179
|
+
private func handleSignOut(provider: String, callback: @escaping (Any?, String?) -> Void) {
|
|
180
|
+
switch provider {
|
|
181
|
+
case "apple":
|
|
182
|
+
UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
|
|
183
|
+
case "google":
|
|
184
|
+
UserDefaults.standard.removeObject(forKey: "vn_google_authCode")
|
|
185
|
+
default:
|
|
186
|
+
break
|
|
187
|
+
}
|
|
188
|
+
callback(nil, nil)
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// MARK: - Get Current User
|
|
192
|
+
|
|
193
|
+
private func handleGetCurrentUser(provider: String, callback: @escaping (Any?, String?) -> Void) {
|
|
194
|
+
switch provider {
|
|
195
|
+
case "apple":
|
|
196
|
+
guard let userId = UserDefaults.standard.string(forKey: "vn_apple_userId") else {
|
|
197
|
+
callback(nil, nil)
|
|
198
|
+
return
|
|
199
|
+
}
|
|
200
|
+
// Verify the credential is still valid
|
|
201
|
+
ASAuthorizationAppleIDProvider().getCredentialState(forUserID: userId) { state, _ in
|
|
202
|
+
switch state {
|
|
203
|
+
case .authorized:
|
|
204
|
+
callback(["userId": userId], nil)
|
|
205
|
+
default:
|
|
206
|
+
UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
|
|
207
|
+
callback(nil, nil)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
case "google":
|
|
211
|
+
if let code = UserDefaults.standard.string(forKey: "vn_google_authCode") {
|
|
212
|
+
callback(["userId": code], nil)
|
|
213
|
+
} else {
|
|
214
|
+
callback(nil, nil)
|
|
215
|
+
}
|
|
216
|
+
default:
|
|
217
|
+
callback(nil, nil)
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
// MARK: - Credential Revocation Observer
|
|
222
|
+
|
|
223
|
+
private func observeAppleCredentialRevocation() {
|
|
224
|
+
credentialObserver = NotificationCenter.default.addObserver(
|
|
225
|
+
forName: ASAuthorizationAppleIDProvider.credentialRevokedNotification,
|
|
226
|
+
object: nil,
|
|
227
|
+
queue: .main
|
|
228
|
+
) { [weak self] _ in
|
|
229
|
+
UserDefaults.standard.removeObject(forKey: "vn_apple_userId")
|
|
230
|
+
self?.bridge?.emitGlobalEvent("auth:appleCredentialRevoked", payload: [:])
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
deinit {
|
|
235
|
+
if let observer = credentialObserver {
|
|
236
|
+
NotificationCenter.default.removeObserver(observer)
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
#endif
|
|
@@ -0,0 +1,213 @@
|
|
|
1
|
+
#if canImport(UIKit)
|
|
2
|
+
import Foundation
|
|
3
|
+
|
|
4
|
+
/// Native module for WebSocket connections.
|
|
5
|
+
///
|
|
6
|
+
/// Supports multiple simultaneous connections keyed by connection ID.
|
|
7
|
+
///
|
|
8
|
+
/// Methods:
|
|
9
|
+
/// - connect(url: String, connectionId: String)
|
|
10
|
+
/// - send(connectionId: String, data: String)
|
|
11
|
+
/// - close(connectionId: String, code: Int?, reason: String?)
|
|
12
|
+
///
|
|
13
|
+
/// Global events dispatched on bridge:
|
|
14
|
+
/// "websocket:open" { connectionId }
|
|
15
|
+
/// "websocket:message" { connectionId, data }
|
|
16
|
+
/// "websocket:close" { connectionId, code, reason }
|
|
17
|
+
/// "websocket:error" { connectionId, message }
|
|
18
|
+
final class WebSocketModule: NativeModule {
|
|
19
|
+
var moduleName: String { "WebSocket" }
|
|
20
|
+
private weak var bridge: NativeBridge?
|
|
21
|
+
|
|
22
|
+
/// Active WebSocket tasks keyed by connectionId
|
|
23
|
+
private var connections: [String: URLSessionWebSocketTask] = [:]
|
|
24
|
+
private var sessions: [String: URLSession] = [:]
|
|
25
|
+
|
|
26
|
+
init(bridge: NativeBridge) {
|
|
27
|
+
self.bridge = bridge
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
func invoke(method: String, args: [Any], callback: @escaping (Any?, String?) -> Void) {
|
|
31
|
+
switch method {
|
|
32
|
+
case "connect":
|
|
33
|
+
guard let url = args.first as? String,
|
|
34
|
+
let connectionId = args.count > 1 ? args[1] as? String : nil else {
|
|
35
|
+
callback(nil, "WebSocketModule: expected (url, connectionId)")
|
|
36
|
+
return
|
|
37
|
+
}
|
|
38
|
+
connect(url: url, connectionId: connectionId, callback: callback)
|
|
39
|
+
|
|
40
|
+
case "send":
|
|
41
|
+
guard let connectionId = args.first as? String,
|
|
42
|
+
let data = args.count > 1 ? args[1] as? String : nil else {
|
|
43
|
+
callback(nil, "WebSocketModule: expected (connectionId, data)")
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
send(connectionId: connectionId, data: data, callback: callback)
|
|
47
|
+
|
|
48
|
+
case "close":
|
|
49
|
+
guard let connectionId = args.first as? String else {
|
|
50
|
+
callback(nil, "WebSocketModule: expected (connectionId)")
|
|
51
|
+
return
|
|
52
|
+
}
|
|
53
|
+
let code = args.count > 1 ? args[1] as? Int : nil
|
|
54
|
+
let reason = args.count > 2 ? args[2] as? String : nil
|
|
55
|
+
close(connectionId: connectionId, code: code, reason: reason, callback: callback)
|
|
56
|
+
|
|
57
|
+
default:
|
|
58
|
+
callback(nil, "WebSocketModule: Unknown method '\(method)'")
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// MARK: - Connect
|
|
63
|
+
|
|
64
|
+
private func connect(url: String, connectionId: String, callback: @escaping (Any?, String?) -> Void) {
|
|
65
|
+
guard let wsURL = URL(string: url) else {
|
|
66
|
+
callback(nil, "WebSocketModule: invalid URL '\(url)'")
|
|
67
|
+
return
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
// Clean up existing connection with same ID if any
|
|
71
|
+
closeConnection(connectionId)
|
|
72
|
+
|
|
73
|
+
let session = URLSession(configuration: .default)
|
|
74
|
+
let task = session.webSocketTask(with: wsURL)
|
|
75
|
+
connections[connectionId] = task
|
|
76
|
+
sessions[connectionId] = session
|
|
77
|
+
|
|
78
|
+
task.resume()
|
|
79
|
+
|
|
80
|
+
// Dispatch open event once resumed
|
|
81
|
+
let weakBridge = bridge
|
|
82
|
+
DispatchQueue.main.async {
|
|
83
|
+
weakBridge?.dispatchGlobalEvent("websocket:open", payload: [
|
|
84
|
+
"connectionId": connectionId
|
|
85
|
+
])
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// Start receive loop
|
|
89
|
+
receiveLoop(connectionId: connectionId, task: task)
|
|
90
|
+
|
|
91
|
+
callback(true, nil)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// MARK: - Receive loop
|
|
95
|
+
|
|
96
|
+
private func receiveLoop(connectionId: String, task: URLSessionWebSocketTask) {
|
|
97
|
+
task.receive { [weak self] result in
|
|
98
|
+
guard let self = self else { return }
|
|
99
|
+
// Check if connection still exists (may have been closed)
|
|
100
|
+
guard self.connections[connectionId] != nil else { return }
|
|
101
|
+
|
|
102
|
+
switch result {
|
|
103
|
+
case .success(let message):
|
|
104
|
+
let data: String
|
|
105
|
+
switch message {
|
|
106
|
+
case .string(let text):
|
|
107
|
+
data = text
|
|
108
|
+
case .data(let bytes):
|
|
109
|
+
data = String(data: bytes, encoding: .utf8) ?? ""
|
|
110
|
+
@unknown default:
|
|
111
|
+
data = ""
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
let weakBridge = self.bridge
|
|
115
|
+
DispatchQueue.main.async {
|
|
116
|
+
weakBridge?.dispatchGlobalEvent("websocket:message", payload: [
|
|
117
|
+
"connectionId": connectionId,
|
|
118
|
+
"data": data
|
|
119
|
+
])
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// Continue receiving
|
|
123
|
+
self.receiveLoop(connectionId: connectionId, task: task)
|
|
124
|
+
|
|
125
|
+
case .failure(let error):
|
|
126
|
+
let weakBridge = self.bridge
|
|
127
|
+
let errorMessage = error.localizedDescription
|
|
128
|
+
DispatchQueue.main.async {
|
|
129
|
+
// Check if this is a normal close or an actual error
|
|
130
|
+
let nsError = error as NSError
|
|
131
|
+
if nsError.domain == NSPOSIXErrorDomain && nsError.code == 57 {
|
|
132
|
+
// Socket not connected — normal close, dispatch close event
|
|
133
|
+
weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
|
|
134
|
+
"connectionId": connectionId,
|
|
135
|
+
"code": 1000,
|
|
136
|
+
"reason": ""
|
|
137
|
+
])
|
|
138
|
+
} else {
|
|
139
|
+
weakBridge?.dispatchGlobalEvent("websocket:error", payload: [
|
|
140
|
+
"connectionId": connectionId,
|
|
141
|
+
"message": errorMessage
|
|
142
|
+
])
|
|
143
|
+
weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
|
|
144
|
+
"connectionId": connectionId,
|
|
145
|
+
"code": 1006,
|
|
146
|
+
"reason": errorMessage
|
|
147
|
+
])
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
self.connections.removeValue(forKey: connectionId)
|
|
151
|
+
self.sessions[connectionId]?.invalidateAndCancel()
|
|
152
|
+
self.sessions.removeValue(forKey: connectionId)
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// MARK: - Send
|
|
158
|
+
|
|
159
|
+
private func send(connectionId: String, data: String, callback: @escaping (Any?, String?) -> Void) {
|
|
160
|
+
guard let task = connections[connectionId] else {
|
|
161
|
+
callback(nil, "WebSocketModule: no connection '\(connectionId)'")
|
|
162
|
+
return
|
|
163
|
+
}
|
|
164
|
+
task.send(.string(data)) { error in
|
|
165
|
+
if let error = error {
|
|
166
|
+
callback(nil, error.localizedDescription)
|
|
167
|
+
} else {
|
|
168
|
+
callback(true, nil)
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
// MARK: - Close
|
|
174
|
+
|
|
175
|
+
private func close(connectionId: String, code: Int?, reason: String?, callback: @escaping (Any?, String?) -> Void) {
|
|
176
|
+
guard let task = connections[connectionId] else {
|
|
177
|
+
callback(nil, nil) // Already closed, not an error
|
|
178
|
+
return
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
let closeCode = URLSessionWebSocketTask.CloseCode(rawValue: code ?? 1000) ?? .normalClosure
|
|
182
|
+
let reasonData = reason?.data(using: .utf8)
|
|
183
|
+
task.cancel(with: closeCode, reason: reasonData)
|
|
184
|
+
|
|
185
|
+
let weakBridge = bridge
|
|
186
|
+
DispatchQueue.main.async {
|
|
187
|
+
weakBridge?.dispatchGlobalEvent("websocket:close", payload: [
|
|
188
|
+
"connectionId": connectionId,
|
|
189
|
+
"code": code ?? 1000,
|
|
190
|
+
"reason": reason ?? ""
|
|
191
|
+
])
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
connections.removeValue(forKey: connectionId)
|
|
195
|
+
sessions[connectionId]?.invalidateAndCancel()
|
|
196
|
+
sessions.removeValue(forKey: connectionId)
|
|
197
|
+
|
|
198
|
+
callback(true, nil)
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
// MARK: - Helpers
|
|
202
|
+
|
|
203
|
+
private func closeConnection(_ connectionId: String) {
|
|
204
|
+
guard let task = connections[connectionId] else { return }
|
|
205
|
+
task.cancel(with: .normalClosure, reason: nil)
|
|
206
|
+
connections.removeValue(forKey: connectionId)
|
|
207
|
+
sessions[connectionId]?.invalidateAndCancel()
|
|
208
|
+
sessions.removeValue(forKey: connectionId)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
func invokeSync(method: String, args: [Any]) -> Any? { nil }
|
|
212
|
+
}
|
|
213
|
+
#endif
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// Placeholder: Vue Native JS bundle will be generated by Vite build pipeline.
|
|
2
|
+
// This file is included as an SPM resource so the package structure is valid.
|
|
3
|
+
// Replace with the actual IIFE bundle from: pnpm build (in the app project).
|
|
4
|
+
(function() {
|
|
5
|
+
if (typeof __VN_log === 'function') {
|
|
6
|
+
__VN_log('vue-native-bundle.js placeholder loaded');
|
|
7
|
+
}
|
|
8
|
+
})();
|