SwiftUI has a unique entry point compared to the traditional AppDelegate which occurs in swift and objective c.
SwiftUI uses @main like below
@main
struct MyNewApp: App {
var body: some Scene {
WindowGroup {
AppView()
}
}
}
In SwiftUI we can get access to the AppDelegate by creating a new class, creating a Window variable and setting up the ZoomSDK here
class AppDelegate: NSObject, UIApplicationDelegate {
static let Shared = AppDelegate()
var window: UIWindow?
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool {
setupSDK(sdkKey: zoomSdkKey, sdkSecret: zoomSdkSecret)
print("didFinishLaunchingWithOptions")
return true
}
func applicationWillEnterForeground(_ application: UIApplication) {
print("applicationWillEnterForeground")
}
func applicationDidBecomeActive(_ application: UIApplication) {
print("applicationDidBecomeActive")
}
func setupSDK(sdkKey: String, sdkSecret: String) {
let context = MobileRTCSDKInitContext()
context.domain = "zoom.us"
context.enableLog = true
let sdkInitializedSuccessfully = MobileRTC.shared().initialize(context)
if sdkInitializedSuccessfully == true, let authorizationService = MobileRTC.shared().getAuthService() {
authorizationService.clientKey = sdkKey
authorizationService.clientSecret = sdkSecret
authorizationService.delegate = self
authorizationService.sdkAuth()
}
}
}
To assign the AuthorizationServiceDelege to self we have to make an extension to our custom AppDelegate
extension AppDelegate: MobileRTCAuthDelegate {
// Result of calling sdkAuth(). MobileRTCAuthError_Success represents a successful authorization.
func onMobileRTCAuthReturn(_ returnValue: MobileRTCAuthError) {
switch returnValue {
case .success:
print("SDK successfully initialized.")
case .keyOrSecretEmpty:
assertionFailure("SDK Key/Secret was not provided. Replace sdkKey and sdkSecret at the top of this file with your SDK Key/Secret.")
case .keyOrSecretWrong, .unknown:
assertionFailure("SDK Key/Secret is not valid.")
default:
assertionFailure("SDK Authorization failed with MobileRTCAuthError: \(returnValue).")
}
}
// Result of calling logIn(). 0 represents a successful login attempt.
func onMobileRTCLoginReturn(_ returnValue: Int) {
switch returnValue {
case 0:
print("Successfully logged in")
// This alerts the ViewController that login was successful. NotificationCenter.default.post(name: Notification.Name("userLoggedIn"), object: nil)
case 1002:
print("Password incorrect")
default:
print("Could not log in. Error code: \(returnValue)")
}
}
// Result of calling logoutRTC(). 0 represents a successful log out attempt.
func onMobileRTCLogoutReturn(_ returnValue: Int) {
switch returnValue {
case 0:
print("Successfully logged out")
default:
print("Could not log out. Error code: \(returnValue)")
}
}
}
Then back at your entry point add a UIApplicationDelegateAdaptor
@main
struct m_CareApp: App {
@UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
...
}
Then for example, in the SwiftUI view in which you want to show the conference call you can do something like this. With getMainWindowToShareWithAppDelegate being the key functions.
struct WelcomeToZoom: View {
@State var startInstandMeeting: Bool = false
@State var loginToMeeting: Bool = false
@State var meetingNumber: String = ""
@State var meetingPassword: String = ""
var body: some View {
VStack(alignment: .center, spacing: 10){
Spacer()
HStack{
Spacer()
TextField("Enter Meeting Number", text: $meetingNumber)
Spacer()
}.padding()
HStack{
Spacer()
TextField("Enter Meeting Passcode", text: $meetingPassword)
Spacer()
}.padding()
Button(action: {
if meetingPassword.count > 0{
self.startInstandMeeting.toggle()
}
}) {
Label("Start Meeting", systemImage: "photo")
}
.padding()
if self.startInstandMeeting{
StartZoomVC(delegate: StartZoomVC.Delegate(), zoomMeetingNumber: $meetingNumber, zoomPasscode: $meetingPassword)
}
Spacer()
}
}
}
struct StartZoomVC: UIViewControllerRepresentable {
@Binding var meetingNumber: String
@Binding var passCode: String
private let delegate: MobileRTCMeetingServiceDelegate
//private let authDelegate: MobileRTCAuthDelegate
init(delegate: MobileRTCMeetingServiceDelegate, zoomMeetingNumber: Binding<String>, zoomPasscode: Binding<String>) {
self._meetingNumber = zoomMeetingNumber
self._passCode = zoomPasscode
self.delegate = delegate
}
func makeUIViewController(context: Context) -> UIViewController {
print("making the view controller")
let newVC = UIViewController()
newVC.view.tag = 83838383
newVC.view.backgroundColor = .red
return newVC
}
func updateUIViewController(_ taskViewController: UIViewController, context: Context) {
askPermissionsForCameraFeed()
print("check video permissions")
}
func askPermissionsForCameraFeed() {
AVCaptureDevice.requestAccess(for: AVMediaType.video) { response in
if response {
//access granted
getMainWindowToShareWithAppDelegate()
} else {
print("wtf")
}
}
}
func getMainWindowToShareWithAppDelegate(){
DispatchQueue.main.async {
let scene = UIApplication.shared.connectedScenes.first
let windowSceneDelegate = scene?.delegate as? UIWindowSceneDelegate
let window = (windowSceneDelegate?.window)!
UIApplication.shared.delegate = AppDelegate.Shared
let delegate = UIApplication.shared.delegate as! AppDelegate
delegate.window = window
print("finding window to provide to zoom sdk")
joinMeeting(meetingNumber: meetingNumber, meetingPassword: passCode)
}
}
func startMeeting() {
// 5. Obtain the MobileRTCMeetingService from the Zoom SDK, this service can start meetings, join meetings, leave meetings, etc.
if let meetingService = MobileRTC.shared().getMeetingService() {
//6. Set the ViewContoller to be the MobileRTCMeetingServiceDelegate
meetingService.delegate = delegate
/*** 5. Create a MobileRTCMeetingStartParam to provide the MobileRTCMeetingService with the necessary info to start an instant meeting. In this case we will use MobileRTCMeetingStartParam4LoginlUser(), since the user has logged into Zoom. ***/
let startMeetingParameters = MobileRTCMeetingStartParam4LoginlUser()
// 6. Call the startMeeting function in MobileRTCMeetingService. The Zoom SDK will handle the UI for you, unless told otherwise.
meetingService.startMeeting(with: startMeetingParameters)
}
}
func logIn(email: String, password: String) {
// 2. Obtain the MobileRTCAuthService from the Zoom SDK, this service can log in a Zoom user, log out a Zoom user, authorize the Zoom SDK etc.
if let authorizationService = MobileRTC.shared().getAuthService() {
// 3. Call the login function in MobileRTCAuthService. This will attempt to log in the user.
authorizationService.login(withEmail: email, password: password, rememberMe: false)
}else {
print("authorization service failed")
}
}
func joinMeeting(meetingNumber: String, meetingPassword: String) {
// Obtain the MobileRTCMeetingService from the Zoom SDK, this service can start meetings, join meetings, leave meetings, etc.
if let meetingService = MobileRTC.shared().getMeetingService() {
// Create a MobileRTCMeetingJoinParam to provide the MobileRTCMeetingService with the necessary info to join a meeting.
// In this case, we will only need to provide a meeting number and password.
// 2. Set the ViewContoller to be the MobileRTCMeetingServiceDelegate
meetingService.delegate = delegate
let joinMeetingParameters = MobileRTCMeetingJoinParam()
joinMeetingParameters.meetingNumber = meetingNumber
joinMeetingParameters.password = meetingPassword
// Call the joinMeeting function in MobileRTCMeetingService. The Zoom SDK will handle the UI for you, unless told otherwise.
// If the meeting number and meeting password are valid, the user will be put into the meeting. A waiting room UI will be presented or the meeting UI will be presented.
DispatchQueue.main.async {
meetingService.joinMeeting(with: joinMeetingParameters)
}
}
}
}
extension StartZoomVC {
class Delegate: NSObject, MobileRTCMeetingServiceDelegate {
func onMeetingError(_ error: MobileRTCMeetError, message: String?) {
switch error {
case .passwordError:
print("Could not join or start meeting because the meeting password was incorrect.")
case .success:
print("onMeetingError : MobileRTCMeetError_Success")
default:
print("Could not join or start meeting with MobileRTCMeetError: \(error) \(message ?? "")")
}
}
func onMeetingEndedReason(_ reason: MobileRTCMeetingEndReason) {
print("Join meeting end reason.")
}
// Is called when the user joins a meeting.
func onJoinMeetingConfirmed() {
print("Join meeting confirmed.")
}
// Is called upon meeting state changes.
func onMeetingStateChange(_ state: MobileRTCMeetingState) {
print("onMeetingStateChange")
switch state {
case .connecting:
print("Connecting")
case .disconnecting:
print("disconnecting")
case .ended:
print("ended")
case .failed:
print("failed")
case .idle:
print("idle")
case .inMeeting:
print("in meeting")
case .inWaitingRoom:
print("in waiting room")
case .joinBO:
print("join bo")
case .leaveBO:
print("leave bo")
case .locked:
print("locked")
case .reconnecting:
print("reconnecting")
case .unknow:
print("unknown")
case .unlocked:
print("unlocked")
case .waitingExternalSessionKey:
print("waiting external session key")
case .waitingForHost:
print("waiting for host")
case .webinarDePromote:
print("de promote")
case .webinarPromote:
print("promote")
default:
print("bad things happened")
}
}
}
}