iosswiftswiftuiuikitdji-sdk

SwiftUI and DJI UX SDK 5 (Beta)


I am trying to integrate UX SDK 5 (Beta 0.4.1) into my SwiftUI app.

As a start I want to display DUXBetaConnectionWidget, DUXBetaFPVWidget and DUXBetaCompassWidget.

I have build two wrapper classes.

The first one is the UIViewControllerRepresantable

struct BetaDjiView<DjiWidget: DUXBetaBaseWidget>: UIViewControllerRepresentable {
    
    typealias UIViewControllerType = BetaViewController<DjiWidget>
    
    func makeUIViewController(context: Context) -> BetaViewController<DjiWidget> {
        return BetaViewController<DjiWidget>()
    }
    
    func updateUIViewController(_ uiViewController: BetaViewController<DjiWidget>, context: Context) { }
}

The second class is another UIViewController wrapper that actually holds the DJI "Widgets".

class BetaViewController<T: DUXBetaBaseWidget> : UIViewController {
    
    var djiWidget = T()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        addChild(djiWidget)
        djiWidget.install(in: self)
        makeConstraints()
    }
    
    func makeConstraints() {
        NSLayoutConstraint.activate([
            djiWidget.view.topAnchor.constraint(equalTo: view.topAnchor),
            djiWidget.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
            djiWidget.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            djiWidget.view.trailingAnchor.constraint(equalTo: view.trailingAnchor)
        ])
    }
    
    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }
    
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
    }
    
    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
    }
}

In my ContentView I am instantiating the widgets like so:

var body: some View {
  GeometryReader { geometry in
    ZStack {
      BetaDjiView<DUXBetaFPVWidget>().frame(width: geometry.size.width, height: geometry.size.height)
      VStack {
        HStack {
          BetaDjiView<DUXBetaConnectionWidget>().frame(width: 25, height: 25)
          Spacer()
        }
        Spacer()
        HStack {
          BetaDjiView<DUXBetaCompassWidget>().frame(width: 75, height: 75)
          Spacer()
        }
      }.padding()
    }
  }
}

The connection to the product in the SDKManager is active.

Here comes the strange part that is driving me nuts:

I connect the phone to the remote, turn on the remote, then the drone. I let the remote and the drone connect.

When I start the app via Xcode everything is fine. The camera feed is being shown and the connection icon is turning green.

enter image description here

Then I stop the app from Xcode and start the app directly from the phone. The app comes up, but the connection icon is not changing and staying red and there is also no camera feed being shown.

enter image description here

When I stream the logs to the console of my Mac, I can see, that the connection to the product is there.

What could this be? Any help highly appreciated.

EDIT 1

This is my Podfile

platform :ios, '11.0'

target 'DjiMobileSdkTest2' do
  use_frameworks!
  pod 'iOS-Color-Picker'
  pod 'DJI-UXSDK-iOS-Beta', '0.4.1'
end

post_install do |installer|
  installer.pods_project.targets.each do |target|
    target.build_configurations.each do |configuration|
      target.build_settings(configuration.name)['ARCHS'] = '$(ARCHS_STANDARD)'
    end
  end
end

EDIT 2

One more additional observation: I remove the app completely from the phone, then start it again from Xcode and I acknowledge the dialogs that ask permission for Bluetooth and Location usage, which I want. Then the app will again not react and stay in its initial state. Only when I restart again via Xcode the connection icon gets green and the video feet is being shown.

EDIT 3

I have made an observation: After restarting my phone and then starting the app directly by tapping the app icon everything works as it should: the app starts, gets connected to the drone, the connection icon turns green and the camera feed is being updated as well. I was able to repeat this several times.


Solution

  • It finally works!

    As explained in this post, I had to re-introduce the AppDelegate into my app with its didFinishLaunchingWithOptions-lifecycle.

    This is how it looked before:

    @main
    struct MyApp: App {
        
        var someClass = SomeClass()
    
        @Environment(\.scenePhase) private var scenePhase
        
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
            .onChange(of: scenePhase) { (newScenePhase) in
                switch newScenePhase {
                case .active:
                    print("active")
                    someClass.doSomethingThatWouldNotWorkBefore()
                case .background:
                    print("background")
                case .inactive:
                    print("inactive")
                @unknown default:
                    print("default")
                }
            }
        }
    }
    

    And this is how it looked after:

    import SwiftUI
    
    class AppDelegate: UIResponder, UIApplicationDelegate {
    
        var someClass = SomeClass()
    
        func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
            someClass.doSomethingThatWouldNotWorkBefore()
            return true
        }
    }
    
    @main
    struct MyApp: App {
        
        @UIApplicationDelegateAdaptor(AppDelegate.self) var appDelegate
        @Environment(\.scenePhase) private var scenePhase
        
        var body: some Scene {
            WindowGroup {
                ContentView()
            }
            .onChange(of: scenePhase) { (newScenePhase) in
                switch newScenePhase {
                case .active:
                    print("active")
                case .background:
                    print("background")
                case .inactive:
                    print("inactive")
                @unknown default:
                    print("default")
                }
            }
        }
    }
    

    As simple as that ;-)

    I am still trying to figure out what the exact difference is and how this does related to app startup and lifecycle, memory management and "those things".