Skip to content
This repository was archived by the owner on Oct 10, 2025. It is now read-only.

Commit ae41b37

Browse files
authored
Merge pull request #13 from magiclabs/jerryliu-sc-54294-mc-native-ios-sdk
Jerryliu sc 54294 mc native ios sdk
2 parents 6a07591 + 754febc commit ae41b37

File tree

8 files changed

+262
-64
lines changed

8 files changed

+262
-64
lines changed

Sources/MagicSDK/Core/Magic.swift

Lines changed: 58 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -8,48 +8,86 @@
88
import MagicSDK_Web3
99
import WebKit
1010

11+
12+
internal enum ProductType{
13+
case MA
14+
case MC
15+
}
16+
1117
/// An instance of the Magic SDK
12-
public class Magic: NSObject {
13-
18+
public class Magic: MagicCore {
19+
1420
// MARK: - Module
1521
public let user: UserModule
1622
public let auth: AuthModule
17-
18-
// MARK: - Property
19-
private let overlay: WebViewController
20-
public var rpcProvider: RpcProvider
21-
23+
2224
/// Shared instance of `Magic`
2325
public static var shared: Magic!
24-
26+
2527
// MARK: - Initialization
26-
28+
2729
/// Initialize an instance of `Magic`
2830
///
2931
/// - Parameters:
3032
/// - apiKey: Your client ID. From https://dashboard.Magic.com
3133
/// - ethNetwork: Network setting
3234
public convenience init(apiKey: String, network: EthNetwork, locale: String = Locale.current.identifier) {
33-
self.init(urlBuilder: URLBuilder(apiKey: apiKey, network: network, locale: locale))
35+
self.init(urlBuilder: URLBuilder(apiKey: apiKey, locale: locale, productType: .MA))
3436
}
35-
37+
3638
public convenience init(apiKey: String, customNode: CustomNodeConfiguration, locale: String = Locale.current.identifier) {
37-
self.init(urlBuilder: URLBuilder(apiKey: apiKey, customNode: customNode, locale: locale))
39+
let urlBuilder = URLBuilder(apiKey: apiKey, customNode: customNode, locale: locale, productType: ProductType.MA)
40+
self.init(urlBuilder: urlBuilder)
3841
}
39-
42+
4043
public convenience init(apiKey: String, locale: String = Locale.current.identifier) {
41-
self.init(urlBuilder: URLBuilder(apiKey: apiKey, network: EthNetwork.mainnet, locale: locale))
44+
self.init(urlBuilder: URLBuilder(apiKey: apiKey, locale: locale, productType: .MA))
4245
}
43-
46+
47+
/// Core constructor
4448
private init(urlBuilder: URLBuilder) {
45-
self.overlay = WebViewController(url: urlBuilder)
46-
self.rpcProvider = RpcProvider(overlay: self.overlay, urlBuilder: urlBuilder)
47-
self.user = UserModule(rpcProvider: self.rpcProvider)
48-
self.auth = AuthModule(rpcProvider: self.rpcProvider)
49-
super.init()
49+
let rpcProvider = RpcProvider(urlBuilder: urlBuilder)
50+
self.user = UserModule(rpcProvider: rpcProvider)
51+
self.auth = AuthModule(rpcProvider: rpcProvider)
52+
super.init(rpcProvider: rpcProvider)
5053
}
5154
}
5255

56+
/// An instance of the Magic SDK
57+
public class MagicConnect: MagicCore {
58+
59+
public let connect: ConnectModule
60+
61+
/// Shared instance of `Magic`
62+
public static var shared: MagicConnect!
63+
64+
public convenience init(apiKey: String) {
65+
let urlBuilder = URLBuilder(apiKey: apiKey, ethNetwork: EthNetwork.mainnet, locale: "en_US", productType: ProductType.MC)
66+
self.init(urlBuilder: urlBuilder)
67+
}
68+
69+
public convenience init(apiKey: String, network: EthNetwork) {
70+
let urlBuilder = URLBuilder(apiKey: apiKey, ethNetwork: network, locale: "en_US", productType: ProductType.MC)
71+
self.init(urlBuilder: urlBuilder)
72+
}
73+
74+
private init(urlBuilder: URLBuilder) {
75+
let rpcProvider = RpcProvider(urlBuilder: urlBuilder)
76+
self.connect = ConnectModule(rpcProvider: rpcProvider)
77+
super.init(rpcProvider: rpcProvider)
78+
}
79+
}
80+
81+
public class MagicCore: NSObject {
82+
83+
public var rpcProvider: RpcProvider
84+
85+
internal init(rpcProvider: RpcProvider) {
86+
self.rpcProvider = rpcProvider
87+
}
88+
}
89+
90+
5391
// Handles Specific RpcError
5492
extension Web3Response {
5593
public var magicAuthError: RpcProvider.ProviderError? {

Sources/MagicSDK/Core/Provider/RpcProvider.swift

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@ public class RpcProvider: NetworkClient, Web3Provider {
2828
let overlay: WebViewController
2929
public let urlBuilder: URLBuilder
3030

31-
required init(overlay: WebViewController, urlBuilder: URLBuilder) {
31+
required init(urlBuilder: URLBuilder) {
32+
self.overlay = WebViewController(url: urlBuilder)
3233
self.urlBuilder = urlBuilder
33-
self.overlay = overlay
3434
super.init()
3535
}
3636

Sources/MagicSDK/Core/Relayer/URLBuilder.swift

Lines changed: 70 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -13,27 +13,19 @@ import Foundation
1313
// Construct a URI with options encoded
1414
//
1515
public struct URLBuilder {
16-
16+
1717
let encodedParams, url: String
1818
static let host = "https://box.magic.link"
19-
// static let host = "http://192.168.0.106:3016"
20-
19+
2120
public let apiKey: String
2221

23-
init(apiKey: String, customNode: CustomNodeConfiguration, locale: String) {
24-
let options = CustomNodeOptions(apiKey: apiKey, customNode: customNode, locale: locale)
25-
26-
let data = try! JSONEncoder().encode(options)
27-
self.init(data: data, host: URLBuilder.host, apiKey: apiKey)
28-
}
29-
30-
init(apiKey: String, network: EthNetwork, locale: String) {
31-
let options = EthNetworkOptions(apiKey: apiKey, network: network, locale: locale)
32-
let data = try! JSONEncoder().encode(options)
33-
self.init(data: data, host: URLBuilder.host, apiKey: apiKey)
22+
init(apiKey: String, customNode: CustomNodeConfiguration? = nil, ethNetwork: EthNetwork? = nil, locale: String, productType: ProductType) {
23+
24+
let data = try! JSONEncoder().encode(paramsEncodable(apiKey: apiKey, ethNetwork: ethNetwork, customNode: customNode, locale: locale, productType: productType))
25+
self.init(data: data, host: URLBuilder.host, apiKey: apiKey, productType: productType)
3426
}
35-
36-
private init(data: Data, host: String, apiKey: String) {
27+
28+
private init(data: Data, host: String, apiKey: String, productType: ProductType) {
3729
let jsonString = String(data: data, encoding: .utf8)!
3830
let string = jsonString.replacingOccurrences(of: "\\", with: "")
3931
// Encode instantiate option to params
@@ -43,44 +35,83 @@ public struct URLBuilder {
4335
}
4436

4537
// MARK: - Options structs
46-
// Here, Struct is more preferable here. Even though, it can't inherit from classes
47-
// Using class will create more duplicate code as all the sub-class
48-
// needs to be override encode function to encode additional property
49-
struct EthNetworkOptions: Encodable {
38+
struct paramsEncodable: Encodable {
5039
let API_KEY: String
51-
let host = URLBuilder.host
52-
let sdk = "magic-sdk-ios"
53-
let ETH_NETWORK: String
5440
let locale: String
55-
let bundleId = Bundle.main.bundleIdentifier
56-
init(apiKey: String, network: EthNetwork, locale: String) {
57-
self.ETH_NETWORK = network.rawValue
41+
let customNode: CustomNodeConfiguration?
42+
let ethNetwork: EthNetwork?
43+
let productType: ProductType
44+
init(apiKey: String, ethNetwork: EthNetwork?, customNode: CustomNodeConfiguration?, locale: String, productType: ProductType) {
45+
self.productType = productType
46+
self.customNode = customNode
47+
self.ethNetwork = ethNetwork
5848
self.API_KEY = apiKey
5949
self.locale = locale
6050
}
61-
}
6251

63-
struct CustomNodeOptions: Encodable {
64-
let API_KEY: String
65-
let host = URLBuilder.host
66-
let sdk = "magic-sdk-ios"
67-
let ETH_NETWORK: CustomNodeConfiguration
68-
let locale: String
69-
let bundleId = Bundle.main.bundleIdentifier
70-
init(apiKey: String, customNode: CustomNodeConfiguration, locale: String) {
71-
self.ETH_NETWORK = customNode
72-
self.API_KEY = apiKey
73-
self.locale = locale
52+
enum CodingKeys: String, CodingKey {
53+
case sdk, bundleId, API_KEY, host, ETH_NETWORK, ext
54+
}
55+
56+
func encode(to encoder: Encoder) throws {
57+
var container = encoder.container(keyedBy: CodingKeys.self)
58+
try container.encode("magic-sdk-ios", forKey: .sdk)
59+
try container.encode(Bundle.main.bundleIdentifier, forKey: .bundleId)
60+
try container.encode(self.API_KEY, forKey: .API_KEY)
61+
try container.encode(URLBuilder.host, forKey: .host)
62+
63+
/// Network
64+
if (customNode != nil) {
65+
try container.encode(customNode, forKey: .ETH_NETWORK)
66+
}
67+
if (ethNetwork != nil) {
68+
try container.encode(ethNetwork?.rawValue, forKey: .ETH_NETWORK)
69+
}
70+
71+
try container.encode(ExtensionObject(productType: productType), forKey: .ext)
7472
}
7573
}
7674
}
7775

76+
// MARK: -- Network
7877
public struct CustomNodeConfiguration: Encodable {
7978
let rpcUrl: String
8079
let chainId: Int?
81-
80+
8281
public init (rpcUrl: String, chainId: Int? = nil) {
8382
self.rpcUrl = rpcUrl
8483
self.chainId = chainId
8584
}
8685
}
86+
87+
88+
// MARK: -- Extension
89+
struct ExtensionObject: Encodable {
90+
91+
let productType: ProductType
92+
93+
init(productType: ProductType) {
94+
self.productType = productType
95+
}
96+
97+
enum CodingKeys: String, CodingKey {
98+
case connect
99+
}
100+
101+
func encode(to encoder: Encoder) throws {
102+
var container = encoder.container(keyedBy: CodingKeys.self)
103+
104+
switch productType {
105+
case .MC:
106+
try container.encode(MCConfig(), forKey: .connect)
107+
break
108+
default:
109+
break
110+
}
111+
112+
}
113+
}
114+
115+
internal struct MCConfig: Encodable {
116+
let mc = true
117+
}

Sources/MagicSDK/Core/Relayer/WebViewController.swift

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -217,11 +217,35 @@ class WebViewController: UIViewController, WKUIDelegate, WKScriptMessageHandler,
217217
webViewFinishLoading = true
218218
do {
219219
try self.dequeue()
220-
} catch {
221-
// handleRollbarError(error)
222-
}
220+
} catch {}
223221
}
224222

223+
// handle external link clicked events
224+
func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
225+
// Check for links.
226+
if navigationAction.navigationType == .linkActivated {
227+
// Make sure the URL is set.
228+
guard let url = navigationAction.request.url else {
229+
decisionHandler(.allow)
230+
return
231+
}
232+
233+
// Check for the scheme component.
234+
let components = URLComponents(url: url, resolvingAgainstBaseURL: false)
235+
if components?.scheme == "http" || components?.scheme == "https" {
236+
// Open the link in the external browser.
237+
UIApplication.shared.open(url)
238+
// Cancel the decisionHandler because we managed the navigationAction.
239+
decisionHandler(.cancel)
240+
} else {
241+
decisionHandler(.allow)
242+
}
243+
} else {
244+
decisionHandler(.allow)
245+
}
246+
}
247+
248+
225249

226250
// MARK: - View
227251

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
//
2+
// ConnectConfiguration.swift
3+
//
4+
//
5+
// Created by Jerry Liu on 9/16/22.
6+
//
7+
8+
import Foundation
9+
10+
public struct RequestUserInfoConfiguration: BaseConfiguration {
11+
12+
///
13+
public var isResponseRequired = false
14+
15+
public init(isResponseRequired: Bool = false) {
16+
self.isResponseRequired = isResponseRequired
17+
}
18+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
//
2+
// ConnectMethod.swift
3+
//
4+
//
5+
// Created by Jerry Liu on 9/6/22.
6+
//
7+
8+
import Foundation
9+
10+
internal enum ConnectMethod: String, CaseIterable {
11+
12+
// MC
13+
case mc_get_wallet_info
14+
case mc_wallet
15+
case mc_request_user_info
16+
case mc_disconnect
17+
}
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
//
2+
// ConnectModule.swift
3+
//
4+
//
5+
// Created by Jerry Liu on 9/6/22.
6+
//
7+
8+
import Foundation
9+
import MagicSDK_Web3
10+
11+
public class ConnectModule: BaseModule {
12+
13+
/**
14+
getWalletInfo
15+
*/
16+
public func getWalletInfo(response: @escaping Web3ResponseCompletion<WalletInfoResponse>) {
17+
18+
let request = BasicRPCRequest(method: ConnectMethod.mc_get_wallet_info.rawValue, params: [])
19+
20+
return self.provider.send(request: request, response: response)
21+
}
22+
23+
24+
/**
25+
showWallet
26+
*/
27+
public func showWallet(response: @escaping Web3ResponseCompletion<Bool>) {
28+
29+
let request = BasicRPCRequest(method: ConnectMethod.mc_wallet.rawValue, params: [])
30+
31+
return self.provider.send(request: request, response: response)
32+
}
33+
34+
/**
35+
requestUserInfo
36+
*/
37+
public func requestUserInfo(_ configuration: RequestUserInfoConfiguration = RequestUserInfoConfiguration(), response: @escaping Web3ResponseCompletion<UserInfoResponse>) {
38+
39+
let request = RPCRequest<[RequestUserInfoConfiguration]>(method: ConnectMethod.mc_request_user_info.rawValue, params: [configuration])
40+
41+
return self.provider.send(request: request, response: response)
42+
}
43+
44+
/**
45+
disconnect
46+
*/
47+
public func disconnect(response: @escaping Web3ResponseCompletion<Bool>) {
48+
49+
let request = BasicRPCRequest(method: ConnectMethod.mc_disconnect.rawValue, params: [])
50+
51+
return self.provider.send(request: request, response: response)
52+
}
53+
}

0 commit comments

Comments
 (0)