Skip to content
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
25 changes: 0 additions & 25 deletions DemoApp/Sources/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,31 +26,6 @@ class AppDelegate: NSObject, UIApplicationDelegate, @MainActor UNUserNotificatio
return true
}

/// Method used to handle custom URL schemes
func application(
_ app: UIApplication,
open url: URL,
options: [UIApplication.OpenURLOptionsKey: Any] = [:]
) -> Bool {
Router.shared.handle(url: url)
return true
}

/// Method used to handle universal deeplinks
func application(
_ application: UIApplication,
continue userActivity: NSUserActivity,
restorationHandler: @escaping (
[UIUserActivityRestoring]?
) -> Void
) -> Bool {
guard let url = userActivity.webpageURL else {
return false
}
Router.shared.handle(url: url)
return true
}

func application(
_ application: UIApplication,
didRegisterForRemoteNotificationsWithDeviceToken deviceToken: Data
Expand Down
14 changes: 14 additions & 0 deletions DemoApp/Sources/Components/Router.swift
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,20 @@ final class Router: ObservableObject {
return
}

let deeplinkCallCid = callCid(
from: deeplinkInfo.callId,
callType: deeplinkInfo.callType
)

if
deeplinkInfo.baseURL == AppEnvironment.baseURL,
appState.activeCall?.cId == deeplinkCallCid {
log.debug(
"Request to handle deeplink \(url) ignored because the call is already active."
)
return
}

if
deeplinkInfo.baseURL != AppEnvironment.baseURL,
let currentUser = appState.currentUser {
Expand Down
31 changes: 16 additions & 15 deletions DemoApp/Sources/Extensions/DemoApp+Sentry.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,14 @@ import Foundation
import Sentry
import StreamVideo

private let terminalLogsEnvironmentKey = "STREAM_VIDEO_TERMINAL_LOGS"

func configureSentry() {
let terminalDestinationTypes: [LogDestination.Type] =
ProcessInfo.processInfo.environment[terminalLogsEnvironmentKey] == "1"
? [ConsoleLogDestination.self]
: []

if AppEnvironment.configuration.isRelease {
// We're tracking Crash Reports / Issues from the Demo App to keep improving the SDK
SentrySDK.start { options in
Expand All @@ -20,24 +27,18 @@ func configureSentry() {
]
}

LogConfig.destinationTypes = resolving(
baseTypes: [
SentryLogDestination.self,
MemoryLogDestination.self,
OSLogDestination.self
],
environment: ProcessInfo.processInfo.environment
)
LogConfig.destinationTypes = [
SentryLogDestination.self,
MemoryLogDestination.self,
OSLogDestination.self
] + terminalDestinationTypes
} else {
LogConfig.level = .debug
LogConfig.webRTCLogsEnabled = true
LogConfig.destinationTypes = resolving(
baseTypes: [
MemoryLogDestination.self,
OSLogDestination.self
],
environment: ProcessInfo.processInfo.environment
)
LogConfig.destinationTypes = [
MemoryLogDestination.self,
OSLogDestination.self
] + terminalDestinationTypes
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,22 +39,7 @@ struct DemoCallingViewModifier: ViewModifier {
.alignedToReadableContentGuide()
.background(appearance.colors.lobbyBackground.edgesIgnoringSafeArea(.all))
.onReceive(appState.$deeplinkInfo) { deeplinkInfo in
guard
!isAnonymous,
deeplinkInfo.callId != self.text.wrappedValue
else { return }

// We may get in this situation when launching the app from a
// deeplink.
if deeplinkInfo.callId.isEmpty {
joinCallIfNeeded(with: self.text.wrappedValue, callType: callType)
} else {
self.text.wrappedValue = deeplinkInfo.callId
joinCallIfNeeded(
with: self.text.wrappedValue,
callType: callType
)
}
autoJoinIfNeeded(from: deeplinkInfo)
}
.onChange(of: viewModel.callingState) { callingState in
switch callingState {
Expand All @@ -76,7 +61,7 @@ struct DemoCallingViewModifier: ViewModifier {
callKitAdapter.registerForIncomingCalls()
callKitAdapter.iconTemplateImageData = UIImage(named: "logo")?.pngData()
configureVideoRenderingOptions()
joinCallIfNeeded(with: text.wrappedValue, callType: callType)
autoJoinIfNeeded(from: appState.deeplinkInfo)
}
.onReceive(appState.$activeCall) { call in
viewModel.setActiveCall(call)
Expand Down Expand Up @@ -113,10 +98,24 @@ struct DemoCallingViewModifier: ViewModifier {
} catch {
log.error(error)
}
AppState.shared.deeplinkInfo = .empty
}
}

private func autoJoinIfNeeded(from deeplinkInfo: DeeplinkInfo) {
guard !isAnonymous, !deeplinkInfo.callId.isEmpty else {
return
}

let resolvedCallType = deeplinkInfo.callType.isEmpty
? callType
: deeplinkInfo.callType

callType = resolvedCallType
text.wrappedValue = deeplinkInfo.callId
appState.deeplinkInfo = .empty
joinCallIfNeeded(with: deeplinkInfo.callId, callType: resolvedCallType)
}

private func configureVideoRenderingOptions() {
InjectedValues[\.videoRenderingOptions] = .init(
backend: AppEnvironment.videoRenderingBackend.rawBackend,
Expand Down
50 changes: 36 additions & 14 deletions SwiftUIDemoAppUITests/Tests/DeeplinkTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,24 +7,14 @@ import XCTest
// Requires running a standalone Sinatra server
final class DeeplinkTests: StreamTestCase {

override static func setUp() {
super.setUp()

// We are launching and terminating the app to ensure the executable
// has been installed.
app.launch()
app.terminate()
}

override func setUpWithError() throws {
launchApp = false
try super.setUpWithError()
}

private enum MockDeeplink {
static let deeplinkUrlWithCallIdInPath: URL = .init(string: "https://getstream.io/video/demos/join/test-call")!
static let customScheme: URL = .init(string: "streamvideo://video/demos?id=test-call")!
static let customSchemeWithCallIdInPath: URL = .init(string: "streamvideo://video/demos/join/test-call")!

static func customScheme(callId: String) -> URL {
.init(string: "streamvideo://video/demos?id=\(callId)")!
}
}

func test_associationFile_validationWasSuccessful() throws {
Expand Down Expand Up @@ -96,4 +86,36 @@ final class DeeplinkTests: StreamTestCase {
.assertParticipantsAreVisible(count: 1)
}
}

func test_customSchemeURL_forActiveCall_doesNotRejoinAfterLeaving() throws {
GIVEN("user starts the call referenced by the deeplink") {
userRobot
.waitForAutoLogin()
.startCall(callId)
}
WHEN("user opens a deeplink for the active call") {
openURL(MockDeeplink.customScheme(callId: callId))
}
AND("user leaves the call") {
userRobot.endCall()
}
THEN("user stays out of the call") {
userRobot.assertThereAreNoCallControls()
XCTAssertTrue(
CallDetailsPage.callIdInputField.wait().exists,
"callIdInputField should appear"
)

let rejoinExpectation = XCTNSPredicateExpectation(
predicate: NSPredicate(format: "exists == true"),
object: CallPage.hangUpButton
)
rejoinExpectation.isInverted = true

XCTAssertEqual(
XCTWaiter.wait(for: [rejoinExpectation], timeout: 3),
.completed
)
}
}
}
Loading