I have been working to try getting Multipeer Connectivity working in our app in a relatively short period of time. Most things have gone fairly smooth but we have hit a really puzzling issue now.
We have all the data being transferred fine when following the happy path but then when trying to implement the error handling... Which is done through turning off the wifi mid transfer.. My code...:
Sharer:
func sendResource(data: Data?, name: String, fileName: String, peerId: MCPeerID){
if data != nil{
let url = createTransferFile(jsonData: data!, name: fileName)
if url != nil{
session.sendResource(at: url!, withName: name, toPeer: peerId, withCompletionHandler: { (error) -> Void in
if error != nil{
NSLog("Error in sending resource send resource: \(error!.localizedDescription)")
}
})
}
}
}
Receiver:
func session(_ session: MCSession, didFinishReceivingResourceWithName resourceName: String, fromPeer peerID: MCPeerID, at localURL: URL, withError error: Error?) {
NSLog("%#", "didFinishReceivingResourceWithName: \(resourceName)")
if error != nil{
NSLog("error in receiving")
}
if resourceName.contains("clinicDetails"){
if error == nil{
if let data = self.readClinicJsonFromFile(path: localURL){
NSLog("passing to broadcast delegate")
sendDelegate?.addClinicDetails(self, clinicDetailsJSON: data)
}else{
NSLog("there was an error in finding the retrieved file in clinic retrieve finished")
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}else{
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}else if resourceName.contains("patients"){
//NSLog("clinicId in retrievePatient: \(json["clinicId"])")
if error == nil{
if let data = self.readPatientJsonFromFile(path: localURL){
NSLog("passing to retrieve patients delegate")
retrievePatientDelegate?.addPatients(self, patientJSON: data , clinicId: resourceName.components(separatedBy: "/")[1])
}else{
NSLog("there was an error in finding the retrieved file in patient retrieve finished")
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}else{
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}else if resourceName == "clinicList"{
if error == nil{
if let data = self.readClinicListJsonFromFile(path: localURL){
NSLog("passing to retrieve retrieveDelegate")
retrieveDelegate?.addClinics(self, clinicsJSON: data["jsonData"] as! [[String:Any]], passcode: data["passcode"] as! String)
}else{
NSLog("there was an error in finding the retrieved file in patient retrieve finished")
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}else{
_ = Util.showAlert(retrievePatientDelegate as! UIViewController, code: 3021, actions: nil, isCustom: true) as! AlertController
}
}
}
The errors we receive:
2017-03-06 16:52:54.416352 DC[2445:1444277] [GCKSession] Failed to send a DTLS packet with 78 bytes; sendmsg error: Can't assign requested address (49).
2017-03-06 16:52:54.416560 DC[2445:1444277] [GCKSession] SSLWrite failed, packet was not sent for participant [05280B9E] channelID [4] DTLS context [0x103043ea0] pCList [0x10e94f960]; osStatus = -9803: errno = Can't assign requested address (49).
These lines print out more based on the amount of progress left.
Then we also get the following stack in xcode (I can't add images directly into my posts yet :< )
Stack Frame from the thread causing the error
It seems like this bug is linked to a bug in apples framework due to the localURL in the didFinishReceivingResourceWithName function not being an optional.The value on error or progress cancelled is nil. I have come to this conclusion after looking through each call in the crashing thread then finding a related SO Post
Related
This question already has answers here:
canOpenURL: failed for URL: "instagram://app" - error: "This app is not allowed to query for scheme instagram"
(4 answers)
Closed 2 years ago.
I'm trying to use SnapKit, specifically Login Kit, and when I try to send the user to Snapchat to log in, I get the message in the debugger :
-canOpenURL: failed for URL: "snapchat://" - error: "This app is not allowed to query for scheme snapchat".
I also get in the debugger:
Warning: Attempt to present <SFSafariViewController: 0x7fb65485e800> on <App.LoginViewController: 0x7fb653f1f5f0> whose view is not in the window hierarchy!
This is the code I have to try and log in:
import UIKit
import SCSDKLoginKit
class LoginViewController: UIViewController {
#IBOutlet weak var loginButton: UIButton!
#IBOutlet weak var messageLabel: UILabel!
#IBAction func Loginn(_ sender: Any) {
SCSDKLoginClient.login(from: LoginViewController()) { (success: Bool, error: Error?) in
if success {
// Needs to be on the main thread to control the UI.
self.displayForLoginState()
}
if let error = error {
// Needs to be on the main thread to control the UI.
DispatchQueue.main.async {
self.messageLabel?.text = String.init(format: "Login failed. Details: %#", error.localizedDescription)
}
}
}
// loginButtonDidTap()
}
}
extension LoginViewController {
fileprivate func displayForLogoutState() {
// Needs to be on the main thread to control the UI.
DispatchQueue.main.async {
self.logoutButton?.isEnabled = false
//self.loginView.isHidden = false
//self.profileView.isHidden = true
self.messageLabel?.text = LoginViewController.DefaultMessage
}
}
fileprivate func displayForLoginState() {
// Needs to be on the main thread to control the UI.
DispatchQueue.main.async {
self.logoutButton?.isEnabled = true
//self.loginView?.isHidden = true
// self.profileView?.isHidden = false
self.messageLabel?.text = LoginViewController.DefaultMessage
}
displayProfile()
}
fileprivate func displayProfile() {
let successBlock = { (response: [AnyHashable: Any]?) in
guard let response = response as? [String: Any],
let data = response["data"] as? [String: Any],
let me = data["me"] as? [String: Any],
let displayName = me["displayName"] as? String,
let bitmoji = me["bitmoji"] as? [String: Any],
let avatar = bitmoji["avatar"] as? String else {
return
}
// Needs to be on the main thread to control the UI.
DispatchQueue.main.async {
self.loadAndDisplayAvatar(url: URL(string: avatar))
self.nameLabel?.text = displayName
}
}
let failureBlock = { (error: Error?, success: Bool) in
if let error = error {
print(String.init(format: "Failed to fetch user data. Details: %#", error.localizedDescription))
}
}
let queryString = "{me{externalId, displayName, bitmoji{avatar}}}"
SCSDKLoginClient.fetchUserData(withQuery: queryString,
variables: nil,
success: successBlock,
failure: failureBlock)
}
Not sure what the next steps are. If you have any ideas, please let me know. Thanks in advance.
You need to add the schemes you try to open in your app in the info.plist file. Add these lines in your info.plist right after the first <dict> keyword you see when you open it as source code.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>snapchat</string>
</array>
I have a problem by using
if let wd = UIApplication.shared.delegate?.window {
var vc = wd!.rootViewController
If I put this piece of code in a Dispatch, the warning message disappear, but the application doesn't display correctly.
If I remove the dispatch, I have warning message.
UIWindow.rootViewController must be used from main thread only
AND
UIApplication.delegate must be used from main thread only
That class is specially for downloading with a progressBar.
public func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
print("Download finished: \(location)")
...
do {
let result = try FileManager.default.replaceItemAt(URL(fileURLWithPath: Constants.Path.temp.stringByAppendingPathComponent(path: "temp.zip")), withItemAt: URL(fileURLWithPath: location.path))
let source = Constants.Path.tempZipFile
let destination = Constants.Path.temp.stringByAppendingPathComponent(path: "dezipped")
var myDict = [String:Any]()
myDict["source"] = source
myDict["destination"] = destination
DispatchQueue.main.async { //IF I REMOVE THIS => PB OR THREAD IN MAIN
if let wd = UIApplication.shared.delegate?.window {
var vc = wd!.rootViewController
if(vc is UINavigationController){
vc = (vc as! UINavigationController).visibleViewController
}
if(vc is WebViewController){
NotificationCenter.default.post(name: .DeflatSynchroFilesWebView, object: myDict, userInfo: nil)
}
else
{
NotificationCenter.default.post(name: .DeflatSynchroFiles, object: myDict, userInfo: nil)
}
}
}
} catch let writeError as NSError {
print("error writing file temp.zip to temp folder")
}
How to remove the warning without bugging my app?
Thanks in advance.
I am not sure if this can help, but to get the rootViewController I always use this:
if let window = UIApplication.shared.keyWindow?.rootViewController {
}
without the delegate
i'm using swift4: i want to login to the app with twitter, but when i presses login with twitter button i got this error:
Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings" UserInfo={NSLocalizedDescription=Callback URL not approved for this client application. Approved callback URLs can be adjusted in your application settings}
error: Optional("Request failed: forbidden (403)")
i'd followed this documentation and set all plist variables and app delegate also,
this is my code in login page:
#IBAction func loginWithTwitter(_ sender: Any) {
TWTRTwitter.sharedInstance().logIn(completion: {
(session, error) in
if let sess = session {
print("session: ",sess.authToken, sess.authTokenSecret, sess.userID, sess.userName)
self.loginWithTwitter(twitter_id: sess.userID, name: sess.userName)
} else {
print("error: ", error?.localizedDescription as Any)
}
})
}
func loginWithTwitter(twitter_id: String, name: String) {
self.deviceMac = UIDevice.current.identifierForVendor!.uuidString
KRProgressHUD.show(withMessage: "انتظر ....")
API.loginWithTwitter(mac:self.deviceMac, twitter_id: twitter_id, name: name, token: self.token) { (error: Error?, success: Bool, value: Any) in
if success {
KRProgressHUD.dismiss()
let json = JSON(value)
print(json)
if(json["token"] != "") {
let token = json["token"].string
let def = UserDefaults.standard
def.set(token, forKey: "token")
def.synchronize()
Common.setIfTwitterLogin(login: token!)
let homeViewController = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "HomeViewController") as! HomeViewController
self.present(homeViewController, animated: false, completion: nil)
} else {
self.errorLable.text = "عذرا لقد حدث خطأ حاول مره أخري"
}
} else {
KRProgressHUD.dismiss()
self.errorLable.text = "عذرا لقد حدث خطأ حاول مره أخري"
if Connectivity.isConnectedToNetwork(){
print("Internet Connection Available!")
}else{
Common.showToast(messsage: "الرجاء التحقق من إتصالك بالإنترنت", view: self.view)
}
}
}
}
and
class func loginWithTwitter(mac:String, twitter_id: String, name: String, token: String, completion: #escaping (_ error: Error?, _ success: Bool,_ value: Any) -> Void) {
let loginURL = URLs.loginWithTwitter
let loginParameters = [
"mac": mac,
"twitter_id": twitter_id,
"token": token,
"name": name]
print(loginURL, loginParameters)
Alamofire.request(loginURL, method: .post, parameters: loginParameters, encoding: URLEncoding.default, headers: nil)
.responseJSON { reponse in
switch reponse.result {
case .failure(let error):
print("error: ", error)
completion(error, false, "")
case .success(let value):
completion(nil, true, value)
}
}
}
i'd set a call back url in twitter developer app setting, any one know what is the problem?
In your twitter dashboard Go to: https://apps.twitter.com Go into the settings tab and add following Callback URL.
twitterkit-<consumerKey>://
i.e. twitterkit-4bvXXXXXXNFfOXXwrXXXXXXmT://
Twitter dev updated there rules, you can open your developer website,find the setting of Callback URLS ,add this one :
For android
twittersdk://
For iOS, please refer
https://stackoverflow.com/a/50850233/5740236
https://stackoverflow.com/a/50662575/5740236
and it will be work, wish to solve your problem
Add twittersdk:// as one callback URL on your twitter app setting https://apps.twitter.com/ then try it. This worked for me.
I use CallKit, at runtime outgoing call I also call this function
private func startCall(handle: String, video: Bool = false, uuid: UUID) {
let handle = CXHandle(type: .phoneNumber, value: handle)
let startCallAction = CXStartCallAction(call: uuid, handle: handle)
startCallAction.isVideo = video
let transaction = CXTransaction()
transaction.addAction(startCallAction)
requestTransaction(transaction)
}
private func requestTransaction(_ transaction: CXTransaction, completion: ((_ error: Error?) -> Void)? = nil) {
callController.request(transaction) { error in
if let error = error {
debugPrint("Error requesting transaction", error.localizedDescription, transaction.actions)
} else {
debugPrint("Requested transaction successfully")
}
completion?(error)
}
}
But I get an error during the transaction request.
Error requesting transaction" "The operation couldn’t be completed. (com.apple.CallKit.error.requesttransaction error 2.)
How can I fix it?
Update: When the device receives incoming calls, all transactions are executed without error.
This was my mistake, since I did not initialize ProviderDelegate, after initialization everything works as it should.
Error Domain=com.spotify.ios-sdk.playback Code=1 "The operation failed due to an unspecified issue." UserInfo={NSLocalizedDescription=The operation failed due to an unspecified issue
Here is my code
func getAlbums(authSession:SPTSession){
SPTPlaylistList.playlists(forUser: authSession.canonicalUsername, withAccessToken: authSession.accessToken) { (error, response) in
if let listPage = response as? SPTPlaylistList, let albums = listPage.items as? [SPTPartialPlaylist]{
for item in albums{
let stringFromUrl = item.uri
// use SPTPlaylistSnapshot to get all the playlists
print("************************\(item.name)************************")
SPTPlaylistSnapshot.playlist(withURI: stringFromUrl, accessToken: authSession.accessToken!) { (error, snap) in
if let s = snap as? SPTPlaylistSnapshot {
print("====================\(s.name)=====================")
// get the tracks for each playlist
SpotifyManager.MyAlbums.append(s)
if SpotifyManager.MyAlbums.count == albums.count{
NotificationCenter.default.post(name: NSNotification.Name(rawValue: relodNotification), object: nil)
}
}
}
}
}
}
}
This error comes from this method
#objc func play() {
print(songInfo.uri)
SpotifyManager.player?.playSpotifyURI(self.songInfo.uri.absoluteString, startingWith: 0, startingWithPosition: 0, callback: { (err) in
print(err.debugDescription)
})
}
if anybody face this type of problem please give me the best solution to play the Spotify music in my app.
Just remove the looping because the player does that automatically for you!