Replay kit Not working IPAD IOS11 BUG - ios

I am using following code to record screen. It is working fine for ios10 and ios9
#IBAction func btnRecordTapped(_ sender: UIButton) {
if RPScreenRecorder.shared().isAvailable {
if #available(iOS 10.0, *) {
RPScreenRecorder.shared().startRecording(handler: { (error) in
guard error == nil else {
print("Record failed with error \(error!.localizedDescription)")
return
}
DispatchQueue.main.async {
sender.removeTarget(self, action: #selector(self.btnRecordTapped(_:)), for: .touchUpInside)
sender.addTarget(self, action: #selector(self.stoprecording(button:)), for: .touchUpInside)
sender.setTitle("Stop", for: .normal)
sender.setTitleColor(.red, for: .normal)
}
})
} else {
RPScreenRecorder.shared().startRecording(withMicrophoneEnabled: false, handler: { (error) in
guard error == nil else {
print("Record failed with error \(error!.localizedDescription)")
return
}
DispatchQueue.main.async {
sender.removeTarget(self, action: #selector(self.btnRecordTapped(_:)), for: .touchUpInside)
sender.addTarget(self, action: #selector(self.stoprecording(button:)), for: .touchUpInside)
sender.setTitle("Stop", for: .normal)
sender.setTitleColor(.red, for: .normal)
}
})
}
} else {
print("Screen Reocrder not availble")
}
}
I can see Prompt for permission in ios10 and ios9 but not for ios11
ios11 Completion ( closure) block never calls
I have already verified that method calls correctly if condition if RPScreenRecorder.shared().isAvailable { Also allows to let in
Please help me if anyone know about it

I had the same problem as you, so I thinked in updating to iOS 11.0.2 and it worked for me! Hope it help you too.
Just in case, here are my methods:
let recorder = RPScreenRecorder.shared()
#IBAction func recordingAction(_ sender: Any) {
if recorder.isRecording {
stopRecordAction()
} else {
startRecordAction()
}
}
func startRecordAction() {
recorder.startRecording{ (error) in
if let error = error {
print("❗️",error)
}
}
}
func stopRecordAction() {
recorder.stopRecording{ (previewVC, error) in
if let previewVC = previewVC {
previewVC.previewControllerDelegate = self
self.present(previewVC, animated: true, completion: nil)
if let error = error {
print("❗️",error)
}
}
}
}
Methods of RPPreviewViewControllerDelegate:
func previewControllerDidFinish(_ previewController: RPPreviewViewController) {
dismiss(animated: true, completion: nil)
}
func previewController(_ previewController: RPPreviewViewController, didFinishWithActivityTypes activityTypes: Set<String>) {
/// This path was obtained by printing the actiong captured in "activityTypes"
if activityTypes.contains("com.apple.UIKit.activity.SaveToCameraRoll") {
recordFinshedMessage()
}
}

Related

google sign in sign in flow canceled iOS

I'm writing an iOS app that has to use google sign in. It compiles fine but when it runs and I try to sign in with a button, the sign in flow is interrupted:
This is the error: Optional("The operation couldn’t be completed. (com.google.GIDSignIn error -4.)")
error with signing in: Optional(Error Domain=com.google.GIDSignIn Code=-5 "The user canceled the sign-in flow." UserInfo={NSLocalizedDescription=The user canceled the sign-in flow.})
In the simulator, when I press the button, it will show the dialog box asking whether it is ok for the app to access google and then it will just disappear after a second or two.
Here is my ViewController:
//
// ViewController.swift
// frcscout
//
// Created by Elliot Scher on 12/20/22..
//
import UIKit
import GoogleSignIn
import GTMSessionFetcher
import GoogleAPIClientForREST
class ViewController: UIViewController {
#IBOutlet weak var signInButton: UIButton!
private let service = GTLRSheetsService()
override func viewDidLoad() {
super.viewDidLoad()
googleSignIn { signInStatus in
if signInStatus == true {
self.signInButton?.setTitle("Sign out", for: .normal)
print("Signed in!")
} else {
self.signInButton?.setTitle("Sign in", for: .normal)
print("Issues with signing in...")
}
}
}
#IBAction func signInPressed(_ sender: UIButton) {
print("Sign in pressed")
let user = GIDSignIn.sharedInstance.currentUser
if (user == nil) {
googleSignIn() { success in
if success == true {
sender.setTitle("Sign out", for: UIControl.State.normal)
} else {
return
}
}
} else {
GIDSignIn.sharedInstance.signOut()
self.service.authorizer = nil
sender.setTitle("Sign in", for: UIControl.State.normal)
}
}
}
extension ViewController {
func googleSignIn(completionHandler: #escaping (Bool) -> Void) {
GIDSignIn.sharedInstance.restorePreviousSignIn { user, error in
if error == nil {
print("Managed to restore previous sign in!\nScopes: \(String(describing: user?.grantedScopes))")
self.requestScopes(googleUser: user!) { success in
if success == true {
completionHandler(true)
} else {
completionHandler(false)
}
}
} else {
print("No previous user!\nThis is the error: \(String(describing: error?.localizedDescription))")
let signInConfig = GIDConfiguration.init(clientID: K.clientID)
GIDSignIn.sharedInstance.signIn(with: signInConfig, presenting: self) { gUser, signInError in
if signInError == nil {
self.requestScopes(googleUser: gUser!) { signInSuccess in
if signInSuccess == true {
completionHandler(true)
} else {
completionHandler(false)
}
}
} else {
print("error with signing in: \(String(describing: signInError)) ")
self.service.authorizer = nil
completionHandler(false)
}
}
}
}
}
func requestScopes(googleUser: GIDGoogleUser, completionHandler: #escaping (Bool) -> Void) {
let grantedScopes = googleUser.grantedScopes
if grantedScopes == nil || !grantedScopes!.contains(K.grantedScopes) {
let additionalScopes = K.additionalScopes
GIDSignIn.sharedInstance.addScopes(additionalScopes, presenting: self) { user, scopeError in
if scopeError == nil {
user?.authentication.do { authentication, err in
if err == nil {
guard let authentication = authentication else { return }
// Get the access token to attach it to a REST or gRPC request.
// let accessToken = authentication.accessToken
let authorizer = authentication.fetcherAuthorizer()
self.service.authorizer = authorizer
completionHandler(true)
} else {
print("Error with auth: \(String(describing: err?.localizedDescription))")
completionHandler(false)
}
}
} else {
completionHandler(false)
print("Error with adding scopes: \(String(describing: scopeError?.localizedDescription))")
}
}
} else {
print("Already contains the scopes!")
completionHandler(true)
}
}
}
Can anyone help me fix this? Thanks!!

Voice recording not working on simulator swift ios

I'm working on voice recorder. When I'm running the code in simulator it's not working.I want the when user record the voice of 1 second upload this voice on backend. How can get the url of voice recorder and stored on backend server? Can we testing the voice recording in simulator or in real mobile device? I've watched some resources that tested on simulator. See my code and guide me best way to record the voice and stored on backend server.
func getDocumentsDirectory() -> URL {
let paths = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)
return paths[0]
}
class ViewController: UIViewController {
#IBOutlet var recordButton: UIButton!
#IBOutlet var playButton: UIButton!
var recordingSession: AVAudioSession!
var audioRecorder: AVAudioRecorder!
var audioPlayer: AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
recordingSession = AVAudioSession.sharedInstance()
do {
try recordingSession.setCategory(.playAndRecord, mode: .default)
try recordingSession.setActive(true)
recordingSession.requestRecordPermission { [unowned self] allowed in
DispatchQueue.main.async {
if allowed {
self.loadRecordingUI()
} else {
// failed to record
}
}
}
} catch {
// failed to record!
}
}
func loadRecordingUI() {
recordButton.isHidden = false
recordButton.setTitle("Tap to Record", for: .normal)
}
#IBAction func recordButtonPressed(_ sender: UIButton) {
if audioRecorder == nil {
startRecording()
} else {
finishRecording(success: true)
}
}
#IBAction func playButtonPressed(_ sender: UIButton) {
if audioPlayer == nil {
startPlayback()
} else {
finishPlayback()
}
}
func startRecording() {
let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.m4a")
let settings = [
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
AVSampleRateKey: 12000,
AVNumberOfChannelsKey: 1,
AVEncoderAudioQualityKey: AVAudioQuality.medium.rawValue
]
do {
audioRecorder = try AVAudioRecorder(url: audioFilename, settings: settings)
audioRecorder.delegate = self
audioRecorder.record()
recordButton.setTitle("Tap to Stop", for: .normal)
} catch {
finishRecording(success: false)
}
}
func finishRecording(success: Bool) {
audioRecorder.stop()
audioRecorder = nil
if success {
recordButton.setTitle("Tap to Re-record", for: .normal)
playButton.setTitle("Play Your Recording", for: .normal)
playButton.isHidden = false
} else {
recordButton.setTitle("Tap to Record", for: .normal)
playButton.isHidden = true
// recording failed :(
}
}
func startPlayback() {
let audioFilename = getDocumentsDirectory().appendingPathComponent("recording.m4a")
do {
audioPlayer = try AVAudioPlayer(contentsOf: audioFilename)
audioPlayer.delegate = self
audioPlayer.play()
playButton.setTitle("Stop Playback", for: .normal)
} catch {
playButton.isHidden = true
// unable to play recording!
}
}
func finishPlayback() {
audioPlayer = nil
playButton.setTitle("Play Your Recording", for: .normal)
}
}
extension ViewController: AVAudioRecorderDelegate {
func audioRecorderDidFinishRecording(_ recorder: AVAudioRecorder, successfully flag: Bool) {
if !flag {
finishRecording(success: false)
}
}
}
extension ViewController: AVAudioPlayerDelegate {
func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
finishPlayback()
}
}

Azure AD B2C integration in SwiftUI App errors with "Authority validation is not supported..."

I currently try to integrate the Azure AD B2C (Email & Sign In with Apple) into my App.
When I preview the login page from the Azure Portal everything looks good and works fine.
But when I open the login page from my App I get the following error:
Error Domain=MSALErrorDomain Code=-50000 "(null)" UserInfo={MSALErrorDescriptionKey=Authority validation is not supported for this type of authority, MSALInternalErrorCodeKey=-42008, MSALCorrelationIDKey=2EFF58A4-24F2-4ABC-8D80-BC96EDD26AB7}
Here is my code for the AD B2C part:
import SwiftUI
import MSAL
class MicrosoftLoginCotroller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let btn = UIButton(frame: CGRect(x: 20, y: self.view.frame.height - 100, width: self.view.frame.width - 40, height: 52))
btn.backgroundColor = .green
btn.setTitle("Lass uns starten!", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
self.view.addSubview(btn)
}
#objc func buttonTapped(_ sender: UIButton) {
do {
let authority = try MSALB2CAuthority(url: URL(string: "https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<policy>")!)
let pcaConfig = MSALPublicClientApplicationConfig(clientId: "my_correct_client_id_from_the_azure_b2c_ad", redirectUri: nil, authority: authority)
let application = try MSALPublicClientApplication(configuration: pcaConfig)
let webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: ["user.read"], webviewParameters: webViewParameters)
application.acquireToken(with: interactiveParameters) { (result, error) in
guard let result = result else {
print("Error MSAL Token")
print(error!)
return
}
if let account = result.account.identifier {
print(account)
UIApplication.shared.windows.first { $0.isKeyWindow }!.rootViewController = UIHostingController(rootView: SignupProcessView())
}
}
} catch {
print("Error MSAL")
print(error)
}
}
}
struct MicrosoftLoginView: UIViewControllerRepresentable {
typealias UIViewControllerType = MicrosoftLoginCotroller
func makeUIViewController(context: UIViewControllerRepresentableContext<MicrosoftLoginView>) -> MicrosoftLoginCotroller {
return MicrosoftLoginCotroller()
}
func updateUIViewController(_ uiViewController: MicrosoftLoginCotroller, context: Context) {
}
}
Do you know where my error is?
Thank you very much!
After looking through 100+ Github issues I found the problem. The SDK doesn't trust the B2C MS domain by default. So you need to add your authoriser as a trusted domain with:
pcaConfig.knownAuthorities = [authority]
The functional code looks like:
import SwiftUI
import MSAL
class MicrosoftLoginCotroller: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
let btn = UIButton(frame: CGRect(x: 20, y: self.view.frame.height - 100, width: self.view.frame.width - 40, height: 52))
btn.backgroundColor = .green
btn.setTitle("Lass uns starten!", for: .normal)
btn.setTitleColor(.white, for: .normal)
btn.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside)
self.view.addSubview(btn)
}
#objc func buttonTapped(_ sender: UIButton) {
do {
let authority = try MSALB2CAuthority(url: URL(string: "https://<tenant>.b2clogin.com/tfp/<tenant>.onmicrosoft.com/<policy>")!)
let pcaConfig = MSALPublicClientApplicationConfig(clientId: "my_correct_client_id_from_the_azure_b2c_ad", redirectUri: nil, authority: authority)
pcaConfig.knownAuthorities = [authority]
let application = try MSALPublicClientApplication(configuration: pcaConfig)
let webViewParameters = MSALWebviewParameters(authPresentationViewController: self)
let interactiveParameters = MSALInteractiveTokenParameters(scopes: ["user.read"], webviewParameters: webViewParameters)
application.acquireToken(with: interactiveParameters) { (result, error) in
guard let result = result else {
print("Error MSAL Token")
print(error!)
return
}
if let account = result.account.identifier {
print(account)
UIApplication.shared.windows.first { $0.isKeyWindow }!.rootViewController = UIHostingController(rootView: SignupProcessView())
}
}
} catch {
print("Error MSAL")
print(error)
}
}
}
struct MicrosoftLoginView: UIViewControllerRepresentable {
typealias UIViewControllerType = MicrosoftLoginCotroller
func makeUIViewController(context: UIViewControllerRepresentableContext<MicrosoftLoginView>) -> MicrosoftLoginCotroller {
return MicrosoftLoginCotroller()
}
func updateUIViewController(_ uiViewController: MicrosoftLoginCotroller, context: Context) {
}
}

Check if playing then change icon on a button

I am currently using the following to change the button icon, when user has press a playVideo.
However, I need something that will check if the media is currently playing and update this with the correct icon?
I am wondering what is the best way to do this.
#IBAction func playVideo(_ sender: Any) {
if(defaultsKeys.musicplayer_connected == "1"){
self.defaults.set("0", forKey: defaultsKeys.musicplayer_connected)
// (sender as! UIButton).setTitle("Pause", for: [])
(sender as! UIButton).setBackgroundImage(UIImage(systemName: "pause.circle"), for: UIControl.State.normal)
MusicPlayer.shared.startBackgroundMusic()
}else
{
self.defaults.set("1", forKey: defaultsKeys.musicplayer_connected)
// (sender as! UIButton).setTitle("Play", for: [])
(sender as! UIButton).setBackgroundImage(UIImage(systemName: "play.circle"), for: UIControl.State.normal)
MusicPlayer.shared.stopBackgroundMusic()
//self.player.pause()
}
}
create a enum to store the state of the player
enum PlayerState {
case playing,paused
}
then create a property observer that will update your button on the change of the value
var playerStateChanged : PlayerState = .playing {
didSet {
switch playerStateChanged {
case .playing:
if #available(iOS 13.0, *) {
yourBtn.setBackgroundImage(UIImage(systemName: "play.circle"), for: .normal)
} else {
// Fallback on earlier versions
}
case .paused:
if #available(iOS 13.0, *) {
yourBtn.setBackgroundImage(UIImage(systemName: "pause.circle"), for: .normal)
} else {
// Fallback on earlier versions
}
}
}
}
Now in your IBAction, update the value of playerStateChanged and it will set the button image accordingly.
#IBAction func playVideo(_ sender: Any) {
// get if player is playing or not and set the value of playerStateChanged
playerStateChanged = .paused
}
You can create a Bool variable and configure the player's image and start/stop actions based on its current state.
Create a computed property isPlaying,
var isPlaying = false {
didSet {
self.playButton.setImage(UIImage(systemName: self.isPlaying ? "play.circle" : "pause.circle"), for: <#T##UIControl.State#>)
self.isPlaying ? MusicPlayer.shared.startBackgroundMusic() : MusicPlayer.shared.stopBackgroundMusic()
}
}
Now, in your playVideo(_:) action method, you need to simply change the state of isPlaying like so,
#IBAction func playVideo(_ sender: Any) {
self.isPlaying = !self.isPlaying
}

DJI drone not connecting (sdkManagerProductDidChange delegate method not called)

I can't seem to get my own app to connect to a particular drone. I have downloaded the bridger app and am using it to debug. I copied the "DJIBaseViewController" from the sample app and have made my own view controller a delegate of it. After adding alot of breakpoints to the code I have found that the major difference between my app and the sample app is that the delegate method "sdkManagerProductDidChange."
// DJIBaseViewController.swift
import UIKit
import DJISDK
protocol DJIProductObjectProtocol {
func fetchAircraft() -> DJIAircraft?
func fetchCamera() -> DJICamera?
func fetchGimbal() -> DJIGimbal?
func fetchFlightController() -> DJIFlightController?
func fetchRemoteController() -> DJIRemoteController?
func fetchBattery() -> DJIBattery?
func fetchAirLink() -> DJIAirLink?
func fetchHandheldController() -> DJIHandheldController?
}
class ConnectedProductManager: DJIProductObjectProtocol {
static let sharedInstance = ConnectedProductManager()
var connectedProduct:DJIBaseProduct? = nil
func fetchAircraft() -> DJIAircraft? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft)
}
return nil
}
func fetchCamera() -> DJICamera? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).camera
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).camera
}
return nil
}
func fetchGimbal() -> DJIGimbal? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).gimbal
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).gimbal
}
return nil
}
func fetchFlightController() -> DJIFlightController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).flightController
}
return nil
}
func fetchRemoteController() -> DJIRemoteController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).remoteController
}
return nil
}
func fetchBattery() -> DJIBattery? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).battery
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).battery
}
return nil
}
func fetchAirLink() -> DJIAirLink? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIAircraft) {
return (self.connectedProduct as! DJIAircraft).airLink
}
else if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).airLink
}
return nil
}
func fetchHandheldController() -> DJIHandheldController? {
if (self.connectedProduct == nil) {
return nil
}
if (self.connectedProduct is DJIHandheld) {
return (self.connectedProduct as! DJIHandheld).handheldController
}
return nil
}
func setDelegate(delegate:DJIBaseProductDelegate?) {
self.connectedProduct?.delegate = delegate
}
}
class DJIBaseViewController: UIViewController, DJIBaseProductDelegate, DJIProductObjectProtocol {
//var connectedProduct:DJIBaseProduct?=nil
var moduleTitle:String?=nil
override func viewDidLoad() {
super.viewDidLoad()
if (moduleTitle != nil) {
self.title = moduleTitle
}
// Do any additional setup after loading the view.
}
override func viewWillAppear(animated: Bool) {
super.viewWillAppear(animated)
if (ConnectedProductManager.sharedInstance.connectedProduct != nil) {
ConnectedProductManager.sharedInstance.setDelegate(self)
}
}
override func viewWillDisappear(
animated: Bool) {
super.viewWillDisappear(animated)
if (ConnectedProductManager.sharedInstance.connectedProduct != nil &&
ConnectedProductManager.sharedInstance.connectedProduct?.delegate === self) {
ConnectedProductManager.sharedInstance.setDelegate(nil)
}
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func product(product: DJIBaseProduct, connectivityChanged isConnected: Bool) {
if isConnected {
NSLog("\(product.model) connected. ")
ConnectedProductManager.sharedInstance.connectedProduct = product
ConnectedProductManager.sharedInstance.setDelegate(self)
}
else {
NSLog("Product disconnected. ")
ConnectedProductManager.sharedInstance.connectedProduct = nil
}
}
func componentWithKey(withKey key: String, changedFrom oldComponent: DJIBaseComponent?, to newComponent: DJIBaseComponent?) {
// (newComponent as? DJICamera)?.delegate = self
if ((newComponent is DJICamera) == true && (self is DJICameraDelegate) == true) {
(newComponent as! DJICamera).delegate = self as? DJICameraDelegate
}
if ((newComponent is DJICamera) == true && (self is DJIPlaybackDelegate) == true) {
(newComponent as! DJICamera).playbackManager?.delegate = self as? DJIPlaybackDelegate
}
if ((newComponent is DJIFlightController) == true && (self is DJIFlightControllerDelegate) == true) {
(newComponent as! DJIFlightController).delegate = self as? DJIFlightControllerDelegate
}
if ((newComponent is DJIBattery) == true && (self is DJIBatteryDelegate) == true) {
(newComponent as! DJIBattery).delegate = self as? DJIBatteryDelegate
}
if ((newComponent is DJIGimbal) == true && (self is DJIGimbalDelegate) == true) {
(newComponent as! DJIGimbal).delegate = self as? DJIGimbalDelegate
}
if ((newComponent is DJIRemoteController) == true && (self is DJIRemoteControllerDelegate) == true) {
(newComponent as! DJIRemoteController).delegate = self as? DJIRemoteControllerDelegate
}
}
func showAlertResult(info:String) {
// create the alert
var message:String? = info
if info.hasSuffix(":nil") {
message = info.stringByReplacingOccurrencesOfString(":nil", withString: " success")
}
let alert = UIAlertController(title: "Message", message: "\(message ?? "")", preferredStyle: .Alert)
// add an action (button)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
// show the alert
self.presentViewController(alert, animated: true, completion: nil)
}
func fetchAircraft() -> DJIAircraft?{
return ConnectedProductManager.sharedInstance.fetchAircraft()
}
func fetchCamera() -> DJICamera? {
return ConnectedProductManager.sharedInstance.fetchCamera()
}
func fetchGimbal() -> DJIGimbal? {
return ConnectedProductManager.sharedInstance.fetchGimbal()
}
func fetchFlightController() -> DJIFlightController? {
return ConnectedProductManager.sharedInstance.fetchFlightController()
}
func fetchRemoteController() -> DJIRemoteController? {
return ConnectedProductManager.sharedInstance.fetchRemoteController()
}
func fetchBattery() -> DJIBattery? {
return ConnectedProductManager.sharedInstance.fetchBattery()
}
func fetchAirLink() -> DJIAirLink? {
return ConnectedProductManager.sharedInstance.fetchAirLink()
}
func fetchHandheldController() -> DJIHandheldController?{
return ConnectedProductManager.sharedInstance.fetchHandheldController()
}
}
The first view that loads after the splashscreen loads is.
// MenuViewController.swift
import UIKit
import DJISDK
let enterDebugMode=true
class MenuViewController: DJIBaseViewController {
#IBOutlet weak var aircraft: UILabel!
#IBOutlet weak var productID: UILabel!
// Do any additional setup after loading the view.
#IBOutlet weak var appConectivity: UILabel!
var connectedProduct:DJIBaseProduct?=nil
var componentDictionary = Dictionary<String, Array<DJIBaseComponent>>()
let APP_KEY = "*******"//Please enter App Key Here
override func viewDidLoad() {
super.viewDidLoad()
let air = self.fetchAircraft()
if air == nil{
aircraft.text?="no aircraft connected"
}
print(air?.model)
initUI();
guard !APP_KEY.isEmpty else {
showAlert("Please enter your app key.")
return
}
DJISDKManager.registerApp(APP_KEY, withDelegate: self)
if DJISDKManager.product() == nil{
productID.text?="Drone Not Connected"
}
else{
productID.text? = "Drone Connected"
}
}
func initUI() {
self.title = "DJI iOS SDK Sample"
//sdkVersionLabel.text = "DJI SDK Version: \(DJISDKManager.getSDKVersion())"
//openComponents.isEnabled = false;
//bluetoothConnectorButton.isEnabled = true;
//productModel.isHidden = true
//productFirmwarePackageVersion.isHidden = true
//debugModeLabel.isHidden = !enterDebugMode
}
func showAlert(msg: String?) {
// create the alert
let alert = UIAlertController(title: "", message: msg, preferredStyle: .Alert)
// add the actions (buttons)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
// show the alert
self.presentViewController(alert, animated: true, completion: nil)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
/*
// MARK: - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
// Get the new view controller using segue.destinationViewController.
// Pass the selected object to the new view controller.
}
*/
}
extension MenuViewController: DJISDKManagerDelegate{
func sdkManagerDidRegisterAppWithError(error: NSError?) {
guard error == nil else {
self.showAlertResult("Error:\(error!.localizedDescription)")
appConectivity.text?="app isn't registering properly"
return
}
//Debug("Registered!")
if enterDebugMode {
DJISDKManager.enterDebugModeWithDebugId("10.202.38.238")
print("WTF")
}else{
//DJISDKManager.enterDebugModeWithDebugId("10.202.38.238")
DJISDKManager.startConnectionToProduct()
}
}
func sdkManagerProductDidChange(From oldProduct: DJIBaseProduct?, To newProduct: DJIBaseProduct?) {
print("entered changed product")
if oldProduct==nil{
print("old product is nill")
}
if newProduct==nil{
print("new product is nill")
}
guard let newProduct = newProduct else
{
appConectivity.text? = "Status: No Product Connected"
ConnectedProductManager.sharedInstance.connectedProduct = nil
//logDebug("Product Disconnected")
return
}
//Updates the product's model
productID.text = "Model: \((newProduct.model)!)"
productID.hidden = false
if let oldProduct = oldProduct {
print("Product changed from: \(oldProduct.model) to \((newProduct.model)!)")
}
//Updates the product's firmware version - COMING SOON
//Updates the product's connection status
//appConectivity.text = "Status: Product Connected"
ConnectedProductManager.sharedInstance.connectedProduct = newProduct
productID.text?="product connected"
//openComponents.isEnabled = true;
//openComponents.alpha = 1.0;
//logDebug("Product Connected")
}
override func product(product: DJIBaseProduct, connectivityChanged isConnected: Bool) {
if isConnected {
print("Status: Product Connected")
//appConectivity.text?="Drone Recognized"
} else {
print("Status: No Product Connected")
//appConectivity.text="Atleast Its trying"
}
}
}
The sdkManager is registering properly with the given app key and bundler identifier. I have also added "Supported external accessory protocols" to my info.plist file with three elements com.dji.video, com.dji.protocol, and com.dji.common.
Been stuck here for quite some time and it's been damn frustrating. Hope someone call help.
Thanks in advance.
I figured it out. The issue here is that the sample app has named its delegate
func sdkManagerProductDidChange(from oldProduct: DJIBaseProduct?, to newProduct: DJIBaseProduct?)
whereas for whatever reason in my sample app the DJISDK knows my delegates function as
func sdkManagerProductDidChangeFrom(oldProduct: DJIBaseProduct?, to newProduct: DJIBaseProduct?)
a bit annoying that that made such a big difference but that's what I get for copying code I guess. Hope this is helpful to someone else down the road...
Cheers
P.S. they may change it again the way I found it is when I typed func into my extension section Xcode spit out a list of functions I could use and the sdkManagerDidChange was one of them with different input variables.
edit: if anyone can explain why it worked on the sample app and not mine that would be sweet too.

Resources