Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

W3m integration update #1373

Merged
merged 12 commits into from
Jun 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions Example/DApp/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
return true
}

func applicationWillEnterForeground(_ application: UIApplication) {
ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: application will enter foreground"))
// Additional code to handle entering the foreground
}

func applicationDidBecomeActive(_ application: UIApplication) {
ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: application did become active"))
// Additional code to handle becoming active
}

// MARK: UISceneSession Lifecycle

func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
Expand All @@ -17,6 +27,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
}

func application(_ application: UIApplication, continue userActivity: NSUserActivity, restorationHandler: @escaping ([any UIUserActivityRestoring]?) -> Void) async -> Bool {
ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: will try to dispatch envelope: \(String(describing: userActivity.webpageURL))"))
guard let url = userActivity.webpageURL,
let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return true
Expand All @@ -32,4 +43,13 @@ class AppDelegate: UIResponder, UIApplicationDelegate {
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}

func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
// Log the event of opening the app via URL
ProfilingService.instance.send(logMessage: .init(message: "AppDelegate: app opened by URL: \(url.absoluteString)"))

// Handle the URL appropriately
try! Sign.instance.dispatchEnvelope(url.absoluteString)

return true
}
}
16 changes: 0 additions & 16 deletions Example/DApp/Common/InputConfig.swift

This file was deleted.

2 changes: 2 additions & 0 deletions Example/DApp/Info.plist
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>MIXPANEL_TOKEN</key>
<string>$(MIXPANEL_TOKEN)</string>
<key>CFBundleURLTypes</key>
<array>
<dict>
Expand Down
5 changes: 5 additions & 0 deletions Example/DApp/Modules/Configuration/ConfigPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ final class ConfigPresenter: ObservableObject, SceneViewModel {

private let router: ConfigRouter

var clientId: String {
guard let clientId = try? Networking.interactor.getClientId() else { return .empty }
return clientId
}

init(
router: ConfigRouter
) {
Expand Down
81 changes: 69 additions & 12 deletions Example/DApp/Modules/Configuration/ConfigView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import SwiftUI

struct ConfigView: View {
@EnvironmentObject var presenter: ConfigPresenter
@State private var copyAlert: Bool = false
@State private var cacheCleanAlert: Bool = false

var body: some View {
NavigationStack {
Expand All @@ -10,22 +12,71 @@ struct ConfigView: View {
.ignoresSafeArea()

ScrollView {
VStack {
Button {
VStack(spacing: 12) {
// Clean Cache Button
Button(action: {
presenter.cleanLinkModeSupportedWalletsCache()
} label: {
HStack {
Spacer()
Text("Clean Link Mode Supported Wallets Cache")
.font(.system(size: 16, weight: .semibold))
.foregroundColor(.white)
.padding(.vertical, 25)
Spacer()
cacheCleanAlert = true
}) {
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 6) {
Text("Clean Cache")
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.font(.system(size: 16, weight: .semibold))

Image(systemName: "trash")
.foregroundColor(.white)

Spacer()
}
.padding(.horizontal, 12)
.padding(.top, 16)

Text("Clean link mode supported wallets cache")
.multilineTextAlignment(.leading)
.foregroundColor(.white.opacity(0.7))
.font(.system(size: 14))
.padding(.horizontal, 12)
.padding(.bottom, 16)
}
.background(Color(red: 95/255, green: 159/255, blue: 248/255))
.cornerRadius(16)
.background(Color(red: 95/255, green: 159/255, blue: 248/255).opacity(0.2).cornerRadius(12))
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 12)
.padding(.top, 10)

// Client ID Row
Button(action: {
UIPasteboard.general.string = presenter.clientId
copyAlert = true
}) {
VStack(alignment: .leading, spacing: 4) {
HStack(spacing: 6) {
Text("Client ID")
.multilineTextAlignment(.leading)
.foregroundColor(.white)
.font(.system(size: 16, weight: .semibold))

Image(systemName: "doc.on.doc")
.foregroundColor(.white)

Spacer()
}
.padding(.horizontal, 12)
.padding(.top, 16)

Text(presenter.clientId)
.multilineTextAlignment(.leading)
.foregroundColor(.white.opacity(0.7))
.font(.system(size: 14))
.padding(.horizontal, 12)
.padding(.bottom, 16)
}
.background(Color(red: 95/255, green: 159/255, blue: 248/255).opacity(0.2).cornerRadius(12))
}
.frame(maxWidth: .infinity)
.padding(.horizontal, 12)
}
.padding(12)
}
Expand All @@ -43,6 +94,12 @@ struct ConfigView: View {
for: .navigationBar
)
}
.alert("Cache cleaned successfully", isPresented: $cacheCleanAlert) {
Button("OK", role: .cancel) { }
}
.alert("Client ID copied to clipboard", isPresented: $copyAlert) {
Button("OK", role: .cancel) { }
}
}
}

Expand Down
34 changes: 18 additions & 16 deletions Example/DApp/Modules/Sign/SignPresenter.swift
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ final class SignPresenter: ObservableObject {
}
Web3Modal.present(from: nil)
}

func connectWalletWithWCM() {
WalletConnectModal.set(sessionParams: .init(
requiredNamespaces: Proposal.requiredNamespaces,
Expand Down Expand Up @@ -158,14 +158,6 @@ final class SignPresenter: ObservableObject {
// MARK: - Private functions
extension SignPresenter {
private func setupInitialState() {
Sign.instance.sessionSettlePublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] _ in
self.router.dismiss()
self.getSession()
}
.store(in: &subscriptions)

getSession()

Sign.instance.sessionDeletePublisher
Expand All @@ -184,6 +176,9 @@ extension SignPresenter {
case .success(let (session, _)):
if session == nil {
AlertPresenter.present(message: "Wallet Succesfully Authenticated", type: .success)
} else {
self.router.dismiss()
self.getSession()
}
break
case .failure(let error):
Expand All @@ -200,20 +195,27 @@ extension SignPresenter {
}
.store(in: &subscriptions)

Sign.instance.sessionsPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] _ in
self.router.dismiss()
self.getSession()
}
.store(in: &subscriptions)
Sign.instance.requestExpirationPublisher
.receive(on: DispatchQueue.main)
.sink { _ in
Task(priority: .high) { ActivityIndicatorManager.shared.stop() }
AlertPresenter.present(message: "Session Request has expired", type: .warning)
}
.store(in: &subscriptions)

Web3Modal.instance.SIWEAuthenticationPublisher
.receive(on: DispatchQueue.main)
.sink { [unowned self] result in
switch result {
case .success((let message, let signature)):
AlertPresenter.present(message: "Authenticated with SIWE", type: .success)
self.router.dismiss()
self.getSession()
case .failure(let error):
AlertPresenter.present(message: "\(error)", type: .warning)
}
}
.store(in: &subscriptions)
}

private func getSession() {
Expand Down
80 changes: 65 additions & 15 deletions Example/DApp/SceneDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {


func scene(_ scene: UIScene, continue userActivity: NSUserActivity) {
ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: will try to dispatch envelope - userActivity: \(String(describing: userActivity.webpageURL))"))
guard let url = userActivity.webpageURL,
let components = URLComponents(url: url, resolvingAgainstBaseURL: true) else {
return
Expand All @@ -27,12 +28,73 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
configureClientsIfNeeded()
setUpProfilingIfNeeded()
ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: willConnectTo : \(String(describing: connectionOptions.userActivities.first?.webpageURL?.absoluteString))"))

configureClientsIfNeeded()
setUpProfilingIfNeeded()


setupWindow(scene: scene)
}

private func setupWindow(scene: UIScene) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)

let viewController = SignModule.create(app: app)
.wrapToNavigationController()

window?.rootViewController = viewController
window?.makeKeyAndVisible()
}

func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: - openURLContexts : \(String(describing: URLContexts.first?.url))"))

guard let context = URLContexts.first else { return }

let url = context.url

guard let components = URLComponents(url: url, resolvingAgainstBaseURL: false),
let queryItems = components.queryItems,
queryItems.contains(where: { $0.name == "wc_ev" }) else {
return
}

do {
try Sign.instance.dispatchEnvelope(url.absoluteString)
} catch {
AlertPresenter.present(message: error.localizedDescription, type: .error)
}
}

func sceneWillEnterForeground(_ scene: UIScene) {
ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: scene will enter foreground"))
// Additional code to handle entering the foreground
}

func sceneDidBecomeActive(_ scene: UIScene) {
ProfilingService.instance.send(logMessage: .init(message: "SceneDelegate: scene did become active"))
// Additional code to handle becoming active
}

private func setUpProfilingIfNeeded() {
if let clientId = try? Networking.interactor.getClientId() {
ProfilingService.instance.setUpProfiling(account: "swift_dapp_\(clientId)", clientId: clientId)
}
}

var clientsConfigured = false
private func configureClientsIfNeeded() {
if clientsConfigured {return}
else {clientsConfigured = true}
Networking.configure(
groupIdentifier: Constants.groupIdentifier,
projectId: InputConfig.projectId,
socketFactory: DefaultSocketFactory()
)
Sign.configure(crypto: DefaultCryptoProvider())

let metadata = AppMetadata(
name: "Swift Dapp",
Expand All @@ -41,7 +103,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
icons: ["https://avatars.githubusercontent.com/u/37784886"],
redirect: try! AppMetadata.Redirect(native: "wcdapp://", universal: "https://lab.web3modal.com/dapp", linkMode: true)
)

Web3Modal.configure(
projectId: InputConfig.projectId,
metadata: metadata,
Expand Down Expand Up @@ -72,7 +134,7 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
projectId: InputConfig.projectId,
metadata: metadata
)

Sign.instance.logger.setLogging(level: .debug)
Networking.instance.setLogging(level: .debug)

Expand All @@ -94,17 +156,5 @@ class SceneDelegate: UIResponder, UIWindowSceneDelegate {
}.store(in: &publishers)

Web3Modal.instance.disableAnalytics()
setupWindow(scene: scene)
}

private func setupWindow(scene: UIScene) {
guard let windowScene = (scene as? UIWindowScene) else { return }
window = UIWindow(windowScene: windowScene)

let viewController = SignModule.create(app: app)
.wrapToNavigationController()

window?.rootViewController = viewController
window?.makeKeyAndVisible()
}
}
5 changes: 5 additions & 0 deletions Example/ExampleApp.xcodeproj/IntegrationTests.xctestplan
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,11 @@
],
"defaultOptions" : {
"codeCoverage" : false,
"commandLineArgumentEntries" : [
{
"argument" : "isTesting"
}
],
"environmentVariableEntries" : [
{
"key" : "RELAY_HOST",
Expand Down
Loading
Loading