@jimrising/easymerchantsdk-react-native 2.4.8 → 2.4.9
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/README.md +1 -1
- package/android/.settings/org.eclipse.buildship.core.prefs +2 -2
- package/android/build.gradle +3 -4
- package/android/config.properties +5 -0
- package/android/config.properties.example +5 -0
- package/ios/ApiManager/APIRequest.swift +0 -3
- package/ios/ApiManager/APIService.swift +0 -2
- package/ios/Classes/EasyMerchantSdk.h +0 -1
- package/ios/Classes/EasyMerchantSdk.m +54 -5
- package/ios/Classes/EasyMerchantSdk.swift +1 -15
- package/ios/Classes/EasyPayViewController.swift +1 -1
- package/ios/EnvironmentConfig.swift +0 -1
- package/ios/Example/SceneDelegate.swift +23 -1
- package/ios/Example/ViewController.swift +0 -8
- package/ios/Extensions/UIFont.swift +0 -1
- package/ios/Extensions/UIViewController+Extension.swift +0 -1
- package/ios/Helper/GrailPayHelper.swift +146 -58
- package/ios/Helper/GrailPayWebViewController.swift +416 -0
- package/ios/Helper/JavaScriptBridge.swift +312 -0
- package/ios/Helper/WebViewConfig.swift +159 -0
- package/ios/Models/Request.swift +48 -204
- package/ios/easymerchantsdk.podspec +2 -2
- package/package.json +1 -1
- package/android/build/generated/source/buildConfig/debug/com/reactlibrary/BuildConfig.java +0 -10
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/AndroidManifest.xml +0 -7
- package/android/build/intermediates/aapt_friendly_merged_manifests/debug/processDebugManifest/aapt/output-metadata.json +0 -18
- package/android/build/intermediates/aar_metadata/debug/writeDebugAarMetadata/aar-metadata.properties +0 -6
- package/android/build/intermediates/annotation_processor_list/debug/javaPreCompileDebug/annotationProcessors.json +0 -1
- package/android/build/intermediates/compile_library_classes_jar/debug/bundleLibCompileToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/compile_r_class_jar/debug/generateDebugRFile/R.jar +0 -0
- package/android/build/intermediates/compile_symbol_list/debug/generateDebugRFile/R.txt +0 -0
- package/android/build/intermediates/incremental/debug/packageDebugResources/compile-file-map.properties +0 -1
- package/android/build/intermediates/incremental/debug/packageDebugResources/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugAssets/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugJniLibFolders/merger.xml +0 -2
- package/android/build/intermediates/incremental/mergeDebugShaders/merger.xml +0 -2
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/BuildConfig.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/javac/debug/compileDebugJavaWithJavac/classes/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/local_only_symbol_list/debug/parseDebugLocalResources/R-def.txt +0 -2
- package/android/build/intermediates/manifest_merge_blame_file/debug/processDebugManifest/manifest-merger-blame-debug-report.txt +0 -7
- package/android/build/intermediates/merged_manifest/debug/processDebugManifest/AndroidManifest.xml +0 -7
- package/android/build/intermediates/navigation_json/debug/extractDeepLinksDebug/navigation.json +0 -1
- package/android/build/intermediates/nested_resources_validation_report/debug/generateDebugResources/nestedResourcesValidationReport.txt +0 -1
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/BuildConfig.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$1.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$2.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule$3.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkModule.class +0 -0
- package/android/build/intermediates/runtime_library_classes_dir/debug/bundleLibRuntimeToDirDebug/com/reactlibrary/RNEasymerchantsdkPackage.class +0 -0
- package/android/build/intermediates/runtime_library_classes_jar/debug/bundleLibRuntimeToJarDebug/classes.jar +0 -0
- package/android/build/intermediates/symbol_list_with_package_name/debug/generateDebugRFile/package-aware-r.txt +0 -1
- package/android/build/outputs/logs/manifest-merger-debug-report.txt +0 -16
- package/android/build/tmp/compileDebugJavaWithJavac/previous-compilation-data.bin +0 -0
- package/ios/Pods/UserDefaults/UserStoreSingleton.swift +0 -425
- package/ios/Pods/ViewControllers/AdditionalInfoVC.swift +0 -2996
- package/ios/Pods/ViewControllers/BaseVC.swift +0 -142
- package/ios/Pods/ViewControllers/BillingInfoVC/BillingInfoVC.swift +0 -3807
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CityListTVC.swift +0 -46
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/CountryListTVC.swift +0 -47
- package/ios/Pods/ViewControllers/BillingInfoVC/Cells/StateListTVC.swift +0 -46
- package/ios/Pods/ViewControllers/Clean Runner_2025-07-23T14-58-05.txt +0 -13
- package/ios/Pods/ViewControllers/CountryListVC.swift +0 -435
- package/ios/Pods/ViewControllers/EmailVerificationVC.swift +0 -300
- package/ios/Pods/ViewControllers/GrailPayVC.swift +0 -492
- package/ios/Pods/ViewControllers/OTPVerificationVC.swift +0 -2278
- package/ios/Pods/ViewControllers/PaymentDoneVC.swift +0 -287
- package/ios/Pods/ViewControllers/PaymentErrorVC.swift +0 -85
- package/ios/Pods/ViewControllers/PaymentInformation/AccountTypeTVC.swift +0 -41
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInfoVC.swift +0 -13115
- package/ios/Pods/ViewControllers/PaymentInformation/PaymentInformationCVC.swift +0 -35
- package/ios/Pods/ViewControllers/PaymentInformation/RecurringTVC.swift +0 -40
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.swift +0 -80
- package/ios/Pods/ViewControllers/PaymentInformation/SavedAccountsTVC/SavedAccountTVC.xib +0 -163
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.swift +0 -81
- package/ios/Pods/ViewControllers/PaymentInformation/SavedCardsTVC/SavedCardsTVC.xib +0 -188
- package/ios/Pods/ViewControllers/PaymentStatusWebViewVC.swift +0 -167
- package/ios/Pods/ViewControllers/TermAndConditionsVC.swift +0 -63
- package/ios/Pods/ViewControllers/ThreeDSecurePaymentDoneVC.swift +0 -1254
- package/ios/easymerchantsdk.storyboard +0 -9089
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
//
|
|
2
|
+
// JavaScriptBridge.swift
|
|
3
|
+
// EasyPay
|
|
4
|
+
//
|
|
5
|
+
// JavaScript bridge handler for GrailPay WebView communication
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import WebKit
|
|
10
|
+
|
|
11
|
+
public class JavaScriptBridge: NSObject, WKScriptMessageHandler {
|
|
12
|
+
weak var webViewController: GrailPayWebViewController?
|
|
13
|
+
|
|
14
|
+
public init(webViewController: GrailPayWebViewController) {
|
|
15
|
+
self.webViewController = webViewController
|
|
16
|
+
super.init()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
20
|
+
if let bodyString = message.body as? String {
|
|
21
|
+
if let data = bodyString.data(using: .utf8),
|
|
22
|
+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
23
|
+
let type = json["type"] as? String {
|
|
24
|
+
handleMessage(type: type, data: json)
|
|
25
|
+
} else {
|
|
26
|
+
handleMessage(type: "message", data: ["message": bodyString])
|
|
27
|
+
}
|
|
28
|
+
return
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
guard let body = message.body as? [String: Any] else { return }
|
|
32
|
+
|
|
33
|
+
if let rawMessage = body["rawMessage"] as? String {
|
|
34
|
+
if let data = rawMessage.data(using: .utf8),
|
|
35
|
+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any],
|
|
36
|
+
let type = json["type"] as? String {
|
|
37
|
+
handleMessage(type: type, data: json)
|
|
38
|
+
} else {
|
|
39
|
+
handleMessage(type: "message", data: ["message": rawMessage])
|
|
40
|
+
}
|
|
41
|
+
return
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if let type = body["type"] as? String {
|
|
45
|
+
handleMessage(type: type, data: body)
|
|
46
|
+
} else if let eventType = body["eventType"] as? String {
|
|
47
|
+
handleMessage(type: eventType, data: body)
|
|
48
|
+
} else if body["result"] != nil {
|
|
49
|
+
handleMessage(type: "onComplete", data: body)
|
|
50
|
+
} else if body["message"] != nil {
|
|
51
|
+
handleMessage(type: "showMessage", data: body)
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
private func handleMessage(type: String, data: [String: Any]) {
|
|
56
|
+
switch type {
|
|
57
|
+
case "postMessage", "showMessage":
|
|
58
|
+
if let message = data["message"] as? String {
|
|
59
|
+
showMessage(message)
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
case "onComplete":
|
|
63
|
+
if let resultJson = data["result"] as? String {
|
|
64
|
+
handleCompletion(resultJson)
|
|
65
|
+
} else if let resultDict = data["result"] as? [String: Any] {
|
|
66
|
+
handleCompletionDict(resultDict)
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
case "closeWebView":
|
|
70
|
+
webViewController?.closePopupFromBridge()
|
|
71
|
+
webViewController?.closeWebView()
|
|
72
|
+
|
|
73
|
+
case "opener_postMessage", "popup_postMessage":
|
|
74
|
+
handlePopupMessage(data)
|
|
75
|
+
|
|
76
|
+
case "closePopup":
|
|
77
|
+
DispatchQueue.main.async {
|
|
78
|
+
self.webViewController?.closePopupFromBridge()
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
case "consoleLog":
|
|
82
|
+
break
|
|
83
|
+
|
|
84
|
+
case "defaultAccountSelected", "linkedDefaultAccount":
|
|
85
|
+
DispatchQueue.main.async {
|
|
86
|
+
var resultData: NSDictionary = [:]
|
|
87
|
+
if let accountData = data["data"] {
|
|
88
|
+
if let accountArray = accountData as? [[String: Any]] {
|
|
89
|
+
resultData = ["data": accountArray]
|
|
90
|
+
} else if let accountDict = accountData as? [String: Any] {
|
|
91
|
+
resultData = ["data": [accountDict]]
|
|
92
|
+
} else {
|
|
93
|
+
resultData = ["data": [accountData]]
|
|
94
|
+
}
|
|
95
|
+
} else {
|
|
96
|
+
resultData = ["data": [data]]
|
|
97
|
+
}
|
|
98
|
+
let result = SDKResult(type: .success, data: resultData)
|
|
99
|
+
self.webViewController?.handleCompletion(result: result)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
case "accountLinked", "linkSuccess", "success", "complete", "done":
|
|
103
|
+
DispatchQueue.main.async {
|
|
104
|
+
var resultData: NSDictionary = [:]
|
|
105
|
+
if let accountData = data["data"] {
|
|
106
|
+
if let accountArray = accountData as? [[String: Any]] {
|
|
107
|
+
resultData = ["data": accountArray]
|
|
108
|
+
} else if let accountDict = accountData as? [String: Any] {
|
|
109
|
+
resultData = ["data": [accountDict]]
|
|
110
|
+
} else {
|
|
111
|
+
resultData = ["data": [accountData]]
|
|
112
|
+
}
|
|
113
|
+
} else {
|
|
114
|
+
resultData = ["data": [data]]
|
|
115
|
+
}
|
|
116
|
+
let result = SDKResult(type: .success, data: resultData)
|
|
117
|
+
self.webViewController?.handleCompletion(result: result)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
case "error", "linkError", "failure":
|
|
121
|
+
DispatchQueue.main.async {
|
|
122
|
+
self.webViewController?.closePopupFromBridge()
|
|
123
|
+
if let errorMessage = data["message"] as? String ?? data["error"] as? String {
|
|
124
|
+
self.webViewController?.showAlert(title: "Error", message: errorMessage)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
case "cancelled", "closed", "dismissed":
|
|
129
|
+
DispatchQueue.main.async {
|
|
130
|
+
let cancelledData: NSDictionary = ["status": false, "message": "User cancelled"]
|
|
131
|
+
let result = SDKResult(type: .cancelled, data: cancelledData)
|
|
132
|
+
self.webViewController?.handleCompletion(result: result)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
default:
|
|
136
|
+
break
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
private func handlePopupMessage(_ data: [String: Any]) {
|
|
141
|
+
guard let message = data["message"] else { return }
|
|
142
|
+
|
|
143
|
+
var oauthData: [String: String] = [:]
|
|
144
|
+
|
|
145
|
+
if let messageDict = message as? [String: Any] {
|
|
146
|
+
if let status = messageDict["status"] as? String { oauthData["status"] = status }
|
|
147
|
+
if let state = messageDict["state"] as? String { oauthData["state"] = state }
|
|
148
|
+
if let url = messageDict["url"] as? String { oauthData["url"] = url }
|
|
149
|
+
if let redirectUrl = messageDict["redirectUrl"] as? String { oauthData["url"] = redirectUrl }
|
|
150
|
+
if let publicToken = messageDict["public_token"] as? String { oauthData["public_token"] = publicToken }
|
|
151
|
+
if let type = messageDict["type"] as? String { oauthData["type"] = type }
|
|
152
|
+
|
|
153
|
+
if let eventData = messageDict["eventData"] as? [String: Any],
|
|
154
|
+
let redirectURL = eventData["redirectURL"] as? String {
|
|
155
|
+
oauthData["url"] = redirectURL
|
|
156
|
+
oauthData["redirectURL"] = redirectURL
|
|
157
|
+
|
|
158
|
+
if let urlComponents = URLComponents(string: redirectURL) {
|
|
159
|
+
urlComponents.queryItems?.forEach { item in
|
|
160
|
+
if let value = item.value {
|
|
161
|
+
oauthData[item.name] = value
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
if messageDict["moneykit"] != nil {
|
|
168
|
+
oauthData["moneykit"] = "true"
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
DispatchQueue.main.async {
|
|
173
|
+
self.webViewController?.forwardOAuthDataToMainWebView(oauthData)
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
func showMessage(_ message: String) {
|
|
178
|
+
DispatchQueue.main.async {
|
|
179
|
+
self.webViewController?.showAlert(title: "GrailPay", message: message)
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
private func handleCompletion(_ resultJson: String) {
|
|
184
|
+
DispatchQueue.main.async {
|
|
185
|
+
if let data = resultJson.data(using: .utf8),
|
|
186
|
+
let json = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
187
|
+
self.handleCompletionDict(json)
|
|
188
|
+
} else {
|
|
189
|
+
self.webViewController?.closePopupFromBridge()
|
|
190
|
+
self.webViewController?.closeWebView()
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
private func handleCompletionDict(_ resultDict: [String: Any]) {
|
|
196
|
+
DispatchQueue.main.async {
|
|
197
|
+
var resultData: NSDictionary = [:]
|
|
198
|
+
|
|
199
|
+
if let data = resultDict["data"] {
|
|
200
|
+
if let dataArray = data as? [[String: Any]] {
|
|
201
|
+
resultData = ["data": dataArray]
|
|
202
|
+
} else if let dataDict = data as? [String: Any] {
|
|
203
|
+
resultData = ["data": [dataDict]]
|
|
204
|
+
} else {
|
|
205
|
+
resultData = ["data": data]
|
|
206
|
+
}
|
|
207
|
+
} else {
|
|
208
|
+
resultData = resultDict as NSDictionary
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
let result = SDKResult(type: .success, data: resultData)
|
|
212
|
+
self.webViewController?.handleCompletion(result: result)
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// MARK: - OAuth Callback Bridge
|
|
218
|
+
public class OAuthCallbackBridge: NSObject, WKScriptMessageHandler {
|
|
219
|
+
let oauthData: [String: String]
|
|
220
|
+
|
|
221
|
+
init(oauthData: [String: String]) {
|
|
222
|
+
self.oauthData = oauthData
|
|
223
|
+
super.init()
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
public func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) {
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
func getOAuthDataJSON() -> String {
|
|
230
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: oauthData, options: []),
|
|
231
|
+
let jsonString = String(data: jsonData, encoding: .utf8) else {
|
|
232
|
+
return "{}"
|
|
233
|
+
}
|
|
234
|
+
return jsonString
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// MARK: - WKWebView Extensions
|
|
239
|
+
extension WKWebView {
|
|
240
|
+
public func injectJavaScript(_ script: String, completion: ((Any?, Error?) -> Void)? = nil) {
|
|
241
|
+
evaluateJavaScript(script) { result, error in
|
|
242
|
+
completion?(result, error)
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
public func injectMessageListener() {
|
|
247
|
+
let script = """
|
|
248
|
+
(function() {
|
|
249
|
+
window.addEventListener('message', function(event) {
|
|
250
|
+
try {
|
|
251
|
+
var data = event.data;
|
|
252
|
+
if (!data || typeof data !== 'object') return;
|
|
253
|
+
|
|
254
|
+
if (data.__bridgeProxy === true && data.message) {
|
|
255
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
256
|
+
window.webkit.messageHandlers.androidBridge.postMessage(data.message);
|
|
257
|
+
}
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const grailpayEvent = new CustomEvent('grailpay-oauth-complete', { detail: data });
|
|
262
|
+
window.dispatchEvent(grailpayEvent);
|
|
263
|
+
} catch (error) {}
|
|
264
|
+
}, false);
|
|
265
|
+
})();
|
|
266
|
+
"""
|
|
267
|
+
injectJavaScript(script)
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public func injectOAuthData(_ oauthData: [String: String]) {
|
|
271
|
+
guard let jsonData = try? JSONSerialization.data(withJSONObject: oauthData, options: []),
|
|
272
|
+
let jsonString = String(data: jsonData, encoding: .utf8) else { return }
|
|
273
|
+
|
|
274
|
+
let script = """
|
|
275
|
+
(function() {
|
|
276
|
+
var oauthData = \(jsonString);
|
|
277
|
+
window.oauthCallbackData = oauthData;
|
|
278
|
+
var redirectURL = oauthData.url || oauthData.redirectURL || window.location.href;
|
|
279
|
+
|
|
280
|
+
window.postMessage({ type: 'link.resume', moneykit: 1, eventData: { redirectURL: redirectURL } }, '*');
|
|
281
|
+
window.postMessage({ type: 'oauth_complete', source: 'popup', url: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
282
|
+
window.postMessage({ type: 'mk-oauth-callback', redirectUrl: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
283
|
+
window.postMessage({ success: true, url: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
284
|
+
|
|
285
|
+
document.querySelectorAll('iframe').forEach(function(iframe) {
|
|
286
|
+
try {
|
|
287
|
+
if (iframe.contentWindow) {
|
|
288
|
+
iframe.contentWindow.postMessage({ type: 'link.resume', moneykit: 1, eventData: { redirectURL: redirectURL } }, '*');
|
|
289
|
+
iframe.contentWindow.postMessage({ type: 'oauth_complete', source: 'popup', url: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
290
|
+
iframe.contentWindow.postMessage({ type: 'mk-oauth-callback', redirectUrl: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
291
|
+
iframe.contentWindow.postMessage({ success: true, url: redirectURL, status: oauthData.status, state: oauthData.state }, '*');
|
|
292
|
+
}
|
|
293
|
+
} catch (e) {}
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
window.dispatchEvent(new CustomEvent('grailpay-oauth-complete', {
|
|
297
|
+
detail: { type: 'oauth_complete', source: 'popup', url: redirectURL, status: oauthData.status, state: oauthData.state },
|
|
298
|
+
bubbles: true
|
|
299
|
+
}));
|
|
300
|
+
|
|
301
|
+
if (typeof window.receiveDeepLinkData !== 'function') {
|
|
302
|
+
window.receiveDeepLinkData = function(data) {
|
|
303
|
+
window.oauthCallbackData = data;
|
|
304
|
+
window.dispatchEvent(new CustomEvent('grailpay-oauth-complete', { detail: data }));
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
window.receiveDeepLinkData(oauthData);
|
|
308
|
+
})();
|
|
309
|
+
"""
|
|
310
|
+
injectJavaScript(script)
|
|
311
|
+
}
|
|
312
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
//
|
|
2
|
+
// WebViewConfig.swift
|
|
3
|
+
// EasyPay
|
|
4
|
+
//
|
|
5
|
+
// WebView configuration utilities for GrailPay
|
|
6
|
+
//
|
|
7
|
+
|
|
8
|
+
import Foundation
|
|
9
|
+
import WebKit
|
|
10
|
+
|
|
11
|
+
public class WebViewConfig {
|
|
12
|
+
public static func createMainWebView(bridge: JavaScriptBridge) -> WKWebView {
|
|
13
|
+
let config = WKWebViewConfiguration()
|
|
14
|
+
config.preferences.javaScriptEnabled = true
|
|
15
|
+
config.preferences.javaScriptCanOpenWindowsAutomatically = true
|
|
16
|
+
config.websiteDataStore = .default()
|
|
17
|
+
|
|
18
|
+
let contentController = WKUserContentController()
|
|
19
|
+
contentController.add(bridge, name: "androidBridge")
|
|
20
|
+
contentController.add(bridge, name: "grailpay")
|
|
21
|
+
contentController.add(bridge, name: "nativeBridge")
|
|
22
|
+
contentController.add(bridge, name: "iosHandler")
|
|
23
|
+
|
|
24
|
+
let bridgeShimScript = WKUserScript(
|
|
25
|
+
source: WebViewConfig.getBridgeShimScript(),
|
|
26
|
+
injectionTime: .atDocumentStart,
|
|
27
|
+
forMainFrameOnly: false
|
|
28
|
+
)
|
|
29
|
+
contentController.addUserScript(bridgeShimScript)
|
|
30
|
+
|
|
31
|
+
config.userContentController = contentController
|
|
32
|
+
config.allowsInlineMediaPlayback = true
|
|
33
|
+
config.mediaTypesRequiringUserActionForPlayback = []
|
|
34
|
+
|
|
35
|
+
let webView = WKWebView(frame: .zero, configuration: config)
|
|
36
|
+
webView.allowsBackForwardNavigationGestures = true
|
|
37
|
+
webView.allowsLinkPreview = true
|
|
38
|
+
webView.customUserAgent = "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"
|
|
39
|
+
|
|
40
|
+
return webView
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
public static func createPopupWebView(with configuration: WKWebViewConfiguration) -> WKWebView {
|
|
44
|
+
let webView = WKWebView(frame: .zero, configuration: configuration)
|
|
45
|
+
webView.allowsBackForwardNavigationGestures = true
|
|
46
|
+
webView.customUserAgent = "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"
|
|
47
|
+
return webView
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
public static func createCallbackWebView(oauthBridge: OAuthCallbackBridge) -> WKWebView {
|
|
51
|
+
let config = WKWebViewConfiguration()
|
|
52
|
+
config.preferences.javaScriptEnabled = true
|
|
53
|
+
|
|
54
|
+
let contentController = WKUserContentController()
|
|
55
|
+
contentController.add(oauthBridge, name: "oauthBridge")
|
|
56
|
+
config.userContentController = contentController
|
|
57
|
+
|
|
58
|
+
let webView = WKWebView(frame: .zero, configuration: config)
|
|
59
|
+
webView.customUserAgent = "Mozilla/5.0 (Linux; Android 13) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Mobile Safari/537.36"
|
|
60
|
+
return webView
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
public static func enableCookies() {
|
|
64
|
+
HTTPCookieStorage.shared.cookieAcceptPolicy = .always
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public static func getBridgeShimScript() -> String {
|
|
68
|
+
"""
|
|
69
|
+
(function() {
|
|
70
|
+
var isMainFrame = (window === window.top);
|
|
71
|
+
|
|
72
|
+
if (!window.AndroidBridge) {
|
|
73
|
+
window.AndroidBridge = {
|
|
74
|
+
postMessage: function(message) {
|
|
75
|
+
try {
|
|
76
|
+
var parsed = typeof message === 'string' ? JSON.parse(message) : message;
|
|
77
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
78
|
+
window.webkit.messageHandlers.androidBridge.postMessage(parsed);
|
|
79
|
+
} else if (window !== window.top) {
|
|
80
|
+
window.parent.postMessage({ __bridgeProxy: true, message: parsed }, '*');
|
|
81
|
+
}
|
|
82
|
+
} catch (e) {
|
|
83
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
84
|
+
window.webkit.messageHandlers.androidBridge.postMessage({ rawMessage: message });
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
showMessage: function(message) {
|
|
89
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
90
|
+
window.webkit.messageHandlers.androidBridge.postMessage({ type: 'showMessage', message: message });
|
|
91
|
+
}
|
|
92
|
+
},
|
|
93
|
+
onComplete: function(result) {
|
|
94
|
+
try {
|
|
95
|
+
var parsed = typeof result === 'string' ? JSON.parse(result) : result;
|
|
96
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
97
|
+
window.webkit.messageHandlers.androidBridge.postMessage({ type: 'onComplete', result: JSON.stringify(parsed) });
|
|
98
|
+
}
|
|
99
|
+
} catch (e) {
|
|
100
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
101
|
+
window.webkit.messageHandlers.androidBridge.postMessage({ type: 'onComplete', result: result });
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
},
|
|
105
|
+
closeWebView: function() {
|
|
106
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
107
|
+
window.webkit.messageHandlers.androidBridge.postMessage({ type: 'closeWebView' });
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
if (isMainFrame) {
|
|
114
|
+
window.addEventListener('message', function(event) {
|
|
115
|
+
try {
|
|
116
|
+
var data = event.data;
|
|
117
|
+
if (data && data.__bridgeProxy === true && data.message) {
|
|
118
|
+
if (window.webkit?.messageHandlers?.androidBridge) {
|
|
119
|
+
window.webkit.messageHandlers.androidBridge.postMessage(data.message);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
} catch (e) {}
|
|
123
|
+
}, false);
|
|
124
|
+
} else {
|
|
125
|
+
if (!window.webkit) window.webkit = {};
|
|
126
|
+
if (!window.webkit.messageHandlers) window.webkit.messageHandlers = {};
|
|
127
|
+
if (!window.webkit.messageHandlers.androidBridge) {
|
|
128
|
+
window.webkit.messageHandlers.androidBridge = {
|
|
129
|
+
postMessage: function(message) {
|
|
130
|
+
window.parent.postMessage({ __bridgeProxy: true, message: message }, '*');
|
|
131
|
+
}
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
if (!window.AndroidBridge) {
|
|
135
|
+
window.AndroidBridge = {
|
|
136
|
+
postMessage: function(message) {
|
|
137
|
+
try {
|
|
138
|
+
var parsed = typeof message === 'string' ? JSON.parse(message) : message;
|
|
139
|
+
window.parent.postMessage({ __bridgeProxy: true, message: parsed }, '*');
|
|
140
|
+
} catch (e) {
|
|
141
|
+
window.parent.postMessage({ __bridgeProxy: true, message: { rawMessage: message } }, '*');
|
|
142
|
+
}
|
|
143
|
+
},
|
|
144
|
+
showMessage: function(msg) {
|
|
145
|
+
window.parent.postMessage({ __bridgeProxy: true, message: { type: 'showMessage', message: msg } }, '*');
|
|
146
|
+
},
|
|
147
|
+
onComplete: function(result) {
|
|
148
|
+
window.parent.postMessage({ __bridgeProxy: true, message: { type: 'onComplete', result: result } }, '*');
|
|
149
|
+
},
|
|
150
|
+
closeWebView: function() {
|
|
151
|
+
window.parent.postMessage({ __bridgeProxy: true, message: { type: 'closeWebView' } }, '*');
|
|
152
|
+
}
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
})();
|
|
157
|
+
"""
|
|
158
|
+
}
|
|
159
|
+
}
|