I have mini-app with Today Extension and I created a custom URL Scheme.
Then after clicking a UIButton in the extension, I've called the open function like
extensionContext?.open(URL(string: "todayextensionexample://inform")!, completionHandler: nil)
The application has started successfully but I cannot debug it.
I try 3 different approaches.
First of all for open debugging Edit Scheme -> Info -> Wait for executable to be launched for executable to be launched in Application scheme but the application waits and there's no launch so there's no debug.
My ( open url: URL ) function is like below:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
NotificationCenter.default.post(name: NSNotification.Name.urlOpenedNotification, object: nil, userInfo: nil)
return true
}
in viewDidLoad method of the ViewController;
override func viewDidLoad() {
super.viewDidLoad()
NotificationCenter.default.addObserver(self, selector: #selector(notificationHandler(_:)), name: NSNotification.Name.urlOpenedNotification, object: nil)
}
This was my second approach.
The 3. approach is that using parsing the URL parameters and logging it like below:
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:]) -> Bool {
let sendingAppID = options[.sourceApplication];
print("source application = \(sendingAppID ?? "Unknown") ")
guard let components = NSURLComponents(url: url, resolvingAgainstBaseURL: true),
let path = components.path,
let params = components.queryItems else {
print("Invalid URL or album path missing")
return false
}
print("components > ", components)
print("path > ", path)
print("params >", params)
var param: [String: Any] = ["components": components, "path": path, "params": params];
NotificationCenter.default.post(name: NSNotification.Name.urlOpenedNotification,
object: nil,
userInfo: param)
return true
}
In 3. approach, I tried that Notification & printing some variables.
Before my questions; I change some of print()'s to NSLog() but in the Device -> Show Logs there's nothing works.
Application has opened with openUrl but I cannot debug it because if I start the TodayExtension target the Application not debugging and otherside if I start Application target, when I click the TodayExtension button then open the app again when it background
func application(_ app: UIApplication, open url: URL ...)
function is not working. I've seen the debugs of the real device but there's nothing to see.
Is there any way to after clicking the button on Today Extension then Xcode has started the main application target and I will able to see the all of the logs?
How can I debug it and see check if its successfully working?
1) Override an initializer in your App Delegate, and add there sleep call.
import UIKit
#UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {
var window: UIWindow?
override init() {
sleep(10000)
}
...
}
2) Install this app on your device or simulator.
3) Put a breakpoint in your code.
4) From the extension, trigger the deeplink.
5) While app is opened and in sleep, connect your Xcode debugger to your app via Xcode app menu (Debug->Attach To Process->< your app name >). This will instantly wake up your app and it will fall into the breakpoint immediately.
Related
On iOS 14 using SwiftUI, I'm currently trying to test Dynamic Links in the situation where the user clicks the link and installs the app, then opens it up and receives information from that link. I followed the recommendations in this post (How can I test Firebase Dynamic Links if my app is not in the App Store?) and also implemented all the AppDelegate functions on the Firebase iOS website.
However, nothing gets called when I open the link, install the app, and then open the app for the first time (It just says "Pasted from Safari"). The only thing that works is clicking Dynamic links when the app is already installed (it opens up the app and calls the url listener functions correctly).
This is the code for generating the link:
let dynamicLink = URL(string: "http://www.mydomainishereIjustremovedit.com/?referrer=\(referrerID)")!
//guard let uid = Auth.auth().currentUser?.uid else { return }
if let referralLink = DynamicLinkComponents(link: dynamicLink, domainURIPrefix: "https://penciltestapp.page.link") {
referralLink.iOSParameters = DynamicLinkIOSParameters(bundleID: "com.penciltestapp.penciltestapp")
//referralLink.iOSParameters?.minimumAppVersion = "1.0"
referralLink.iOSParameters?.appStoreID = "962194608" // Opens up a random app on the app store. Just click this to open the app store, and then install your app from XCode
referralLink.shorten { (shortURL, warnings, error) in
if let error = error {
print(error.localizedDescription)
return
}
self.inviteURL = shortURL
}
}
Dont' forget to implement also this, this was missing in my case
func application(_ app: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any]) -> Bool {
return application(app, open: url,
sourceApplication: options[UIApplication.OpenURLOptionsKey.sourceApplication] as? String,
annotation: "")
}
I use in my app url scheme and I don't know why sometime when I click on URL (e.g. https://api.domain.com/menu?id=7ee5232764-0a79-4afe) iOS opens my app (correct) and 1 second later opens App Store application (not correct). This is my openUrl's method:
func application(_ application: UIApplication, open url: URL, options: [UIApplication.OpenURLOptionsKey : Any] = [:] ) -> Bool {
let components = url.absoluteString.components(separatedBy: "/")
if components.contains("menus") {
let menuId = url.lastPathComponent
let menu = Menu(id: menuId)
SessionManager.shared.navigationManager.present(NavigationItem.menu(menu: menu).viewController, animated: true, completion: nil)
return true
} else {
return false
}
}
Resolved! Bug is on the web side where they have activated a JS timeout that they don't stop after app is opened.
I'm trying to post some content to twitter from my app, and since iOs 11 unfortunately the old way don't work anymore so I'm implementing twitterKit and finding some spikes.
When I don't have the app installed, it runs the completion block below, which is weird because I had to dismiss the alert myself manually, as the alert don't have any buttons to do it.
But my real problem is that I have the twitter app installed and I'm loggued in. But I'm unable to detect it with twitter kit.
And when I press the share to twitter button, the app switch to a new view, were it asks me to connect my app to my twitter (If I'm not loggued in I have a login and password box but the result is always the same...)
When I press "Connect", the view goes back to my app and nothing happens, the completion block is never called... I'm working in iOs 11 and x-code 9 but I've tried the same aproach with iOs 10 and I get the same result. Twitter login is never detected.
This is the code I'm running, any help would be apreciated:
if (Twitter.sharedInstance().sessionStore.hasLoggedInUsers()) {
// App must have at least one logged-in user to compose a Tweet
let composer = TWTRComposerViewController.emptyComposer()
present(composer, animated: false, completion: {
print("This code never runs")
})
} else {
// Log in
Twitter.sharedInstance().logIn { session, error in
if session != nil {
// Log in succeeded / Never happens
let composer = TWTRComposerViewController.emptyComposer()
composer.delegate = self
self.present(composer, animated: true, completion: {
print ("This code never runs")
})
} else {
let alert = UIAlertController(title: "No Twitter Accounts Available", message: "You must log in before presenting a composer.", preferredStyle: .alert)
//Only happens if I don't have the twitter app installed on my device
self.present(alert, animated: false, completion: {
print ("not loggued in")
/*
manual dismission of the prompt as it don't have
any button
*/
sleep(3)
alert.dismiss(animated: true, completion: nil)
})
}
}
}
In the console I'm getting this error:
[Snapshotting] Snapshotting a view (0x105977000, UIKeyboardImpl) that has not been rendered at least once requires afterScreenUpdates:YES.
EDIT: I solved it adding this method in appDelegate:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
return Twitter.sharedInstance().application(app, open: url, options: options)
}
As you found out, you need to let the TwitterKit to handle reopening the app when it's redirected back from twitter:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let twtrHandled = TWTRTwitter.sharedInstance().application(app, open: url, options: options)
return twtrHandled
}
If you have several kits there that can handle URL, this is the way I handle it (here I use also facebook SDK, and Branch SDK):
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
let branchHandled = Branch.getInstance().application(app, open: url, options: options)
let fbHandled = SDKApplicationDelegate.shared.application(app, open: url, options: options)
let twtrHandled = TWTRTwitter.sharedInstance().application(app, open: url, options: options)
return branchHandled || fbHandled || twtrHandled
}
I am developing a very basic iOS app with Swift. Just to read the heart rate data. I am using SFSafariViewController. As known, I first need to register my app on dev.fitbit.com. The registration form requires a callback URL to be entered.
After logging in successfully, FitBit always redirects me back to that entered callback URL. What should I do/code/configure to be able to redirect user back to my iOS app after logging in successfully?
What you need to do is to add the application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool function to your AppDelegate and then create an url scheme for your application as an identifier. To create an url scheme go to your application target > Info > URL Types (at the bottom). Then just add the following in your AppDelegate:
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
DispatchQueue.main.async {
// Conctrol so that we´re coming from the right application
if (url.scheme == "The url scheme that you created"){
// Navigate to the viewController you want
let storyboard = UIStoryboard(name: "Main", bundle: nil)
let controller = storyboard.instantiateViewController(withIdentifier: "WebView") as! WebViewController
self.window?.rootViewController!.present(controller, animated: true, completion: { () -> Void in
})
}
}
return true
}
Try using below 3 steps in your application.
You are using "fitbit", so I am considering your are using OAuth2.0 for login and get access-token.
Step 1 : Set up you URL Schemes.
Step 2 : In your AppDelegate class
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
if (url.host == "oauth-swift") {
OAuthSwift.handle(url: url)
}
return true
}
In Above function what we did is, we check the URL comes to handleOpenUrl method, and check weather it is the right url call back is coming or not.
Step 3 : Set the proper call back URL in you OAuth Handler.
oauthswift = OAuth2Swift(
consumerKey: "********",
consumerSecret: "********",
authorizeUrl: "your authorisation url",
responseType: "token"
)
let handle = oauthswift.authorize(
withCallbackURL: URL(string: "oauth-swift://oauth-callback/fitbit")!,
scope: "your application scope", state:"state",
success: { credential, response, parameters in
print(credential.oauth_token)
},
failure: { error in
print(error.localizedDescription)
}
)
In above step, we set the call back url starting with "oauth-swift:", so it will be work as a host of your call back url.
Image and Code Courtesy : I have tried to explain a solution of your
problem in easy words. And all information of this answers are
originally documented and explained on this URL :
https://github.com/OAuthSwift/OAuthSwift
I am making an Apple Watch app. One of the buttons will open the iphone app connected to the watch app.
What code do I use to do this?
I don't know what to even try?
Note: I am using swift for this project.
WatchKit doesn't include the ability to open the host iOS app in the foreground. The best you can do is open it in the background using openParentApplication:reply:.
If you need the user to do something in your iOS app, consider making use of Handoff.
It is not possible to activate an inactive iPhone app from the Watch. It is, however, possible to call the iPhone app to perform a task or to ask for data. See here: Calling parent application from Watch app
You can only open the iPhone app in the background by the following method:
Swift:
openParentApplication([ParentApp], reply:[Reply])
Objective-C:
openParentApplication:reply:
There is no ability to open the parent app in the foreground.
Note: To send data to iOS app in the background, use the first method.
Note: According to bgilham,
If you need the user to do something in your iOS app, consider making use of Handoff.
If you need to open your parent app in the foreground, use Handoff!
https://developer.apple.com/handoff/
Example:
Somewhere shared for both:
static let sharedUserActivityType = "com.yourcompany.yourapp.youraction"
static let sharedIdentifierKey = "identifier"
on your Watch:
updateUserActivity(sharedUserActivityType, userInfo: [sharedIdentifierKey : 123456], webpageURL: nil)
on your iPhone in App Delegate:
func application(application: UIApplication, willContinueUserActivityWithType userActivityType: String) -> Bool {
if (userActivityType == sharedUserActivityType) {
return true
}
return false
}
func application(application: UIApplication, continueUserActivity userActivity: NSUserActivity, restorationHandler: ([AnyObject]!) -> Void) -> Bool {
if (userActivity.activityType == sharedUserActivityType) {
if let userInfo = userActivity.userInfo as? [String : AnyObject] {
if let identifier = userInfo[sharedIdentifierKey] as? Int {
//Do something
let alert = UIAlertView(title: "Handoff", message: "Handoff has been triggered for identifier \(identifier)" , delegate: nil, cancelButtonTitle: "Thanks for the info!")
alert.show()
return true
}
}
}
return false
}
And finally (this step is important!!!): In your Info.plist(s)