Using openURL to send an email from Yahoo Mail client - ios

What are the openURL parameters for Yahoo Mail?
"ymail:" appears to work, but it just simply opens up the application. I can't seem to figure out how to pre-fill the recipient address.

Got it
"ymail://mail/compose?subject=Subject&to=email#gmail.com&body=message_content"
SWIFT 3.0
if let appSettings = URL(string:"ymail://mail/compose?subject=Subject&to=email#gmail.com&body=message_content") {
UIApplication.shared.open(appSettings, completionHandler: { (success) in})
}
Don't forget to add "ymail" into LSApplicationQueriesSchemes in your Info.plist

Related

Testing passwordless auth in Firebase test lab for iOS

I am trying to figure out how to perform e2e test via firebase test lab for iOS that allow to check passwordless authentication flow, which essentially should do following
Enters email within my app
Firebase sends auth link to such email
Somehow I need to be logged into such email somewhere in firebases test device, I assume either in mail app, or gmail?
I need to know when new email arrives and open it
Once I opened an email I need to click on auth link
This should bring me back into the app and authenticate
My biggest issue at the moment is figuring out steps that happen outside my app i.e. how can I prepare for this test and log in under my email address (is it better to log into gmail in safari for example or somehow add this acc to apples mail app?).
Testing email
In my experience, testing your own code to see if an email was sent is not straightforward beyond checking if the method call you expect to send the email has happened.
Add on top of that using Firebase, which does not expose its underlying email send code, and that looks like a challenge to me.
In terms of testing, I suggest you assert that your method calls to send email happened or that the relevant code path was reached. In Firebase web, this looks like:
firebase.auth().sendSignInLinkToEmail(email, actionCodeSettings)
.then(function() {
// The link was successfully sent. Inform the user.
// Save the email locally so you don't need to ask the user for it again
// if they open the link on the same device.
window.localStorage.setItem('emailForSignIn', email);
// TODO save email to something accessible in your iOS tests
// TODO In your tests, confirm that email was saved after it was sent
})
.catch(function(error) {
// Some error occurred, you can inspect the code: error.code
});
See: https://firebase.google.com/docs/auth/web/email-link-auth#send_an_authentication_link_to_the_users_email_address
Another option:
You could setup a test user with an email address on a mail server that you manage, and check for incoming mail for that test user with your own custom mail reading code.
I would use Firebase Admin tools for this: https://firebase.google.com/docs/auth/admin/manage-users#create_a_user
I think you should first take a look at firebase docs for iOS on how to create dynamic links that you can use for email auth.
https://firebase.google.com/docs/auth/ios/email-link-auth
https://firebase.google.com/docs/auth/ios/passing-state-in-email-actions#configuring_firebase_dynamic_links
After you're done with those two check out the following code:
func application(_ application: UIApplication, open url: URL, sourceApplication: String?, annotation: Any) -> Bool {
// [END old_delegate]
if handlePasswordlessSignIn(withURL: url) {
return true
}
}
func handlePasswordlessSignIn(withURL url: URL) -> Bool {
let link = url.absoluteString
// [START is_signin_link]
if Auth.auth().isSignIn(withEmailLink: link) {
// [END is_signin_link]
UserDefaults.standard.set(link, forKey: "Link")
(window?.rootViewController as? UINavigationController)?.popToRootViewController(animated: false)
window?.rootViewController?.children[0].performSegue(withIdentifier: "passwordless", sender: nil)
return true
}
return false
}
This is just an example on how you can handle the deep link in your app after the user taps the link. The delegate method
func application(_ application: UIApplication, open url: URL,
sourceApplication: String?, annotation: Any) -> Bool
in AppDelegate is used for all deep links into an app. You could set up for example your own scheme that your app conforms to. And you can send url type links with your custom scheme into your app from the browser for example.
To do this just Open Xcode, go to Project Settings -> Info, and add inside ‘The URL Types” section a new URL scheme. Add something of the sort of com.myApp in order for it to be as unizue as possible. Then you can just type into a browser com.myApp://main and handle that in the appDelegate.
Edit: It says so in their docs that you can present a prompt inside the app for the user to input the email. Where the user opens his email from isn't really your concern as long as your dynamic link is set up properly.

Authorization callback URL GitHub

I'm beginning iOS developer. I create an application that uses GitHub authorization. When I register a new OAuth application in GitHub developer program I must enter Authorization callback URL. But I do not have any site for my app. What do I need to specify in this field?
You can use deep linking.
you can read more about it here
The deeplink will try to open the app or redirect to it. The web browser or SFAuthenticationSession will close the browser and call the completion hander where you can check for the response code without any implementation for the deeplink.
To add the deep link in the app you can this below:
Select the project in Xcode navigator.
then select your target that you want to add the deep link to it.
select info from the top bar
at the bottom open the URL Types
add a name for the scheme
when you generate the URL for the oauth you can pass anything you want I just pass login in this example:
func getAuthenticateURL() -> URL {
var urlComponent = URLComponents(string: "https://github.com/login/oauth/authorize")!
var queryItems = urlComponent.queryItems ?? []
queryItems.append(URLQueryItem(name: "client_id", value: "YOUR_CLIENT_ID_HERE"))
queryItems.append(URLQueryItem(name: "redirect_uri", value: "APP_SCHEME_GOES_HERE://login"))
urlComponent.queryItems = queryItems
return urlComponent.url!
}
Then when you need to login do this:
import SafariServices
var authSession: SFAuthenticationSession?
func authenticate(with url: URL, completion: #escaping ((_ token: String?, _ error: Error?) -> Void)) {
authSession?.cancel()
authSession = SFAuthenticationSession(url: url, callbackURLScheme: nil, completionHandler: { url, error in
//get the token and call the completion handler
})
authSession?.start()
}
or use ASWebAuthenticationSession the same way if you're on iOS 12
Using SFAuthenticationSession you can do something like this. On your App add URLType:
Then on GitHub 'Developer Settings' for your app, add Authorization callback URL like this:
This way, after you login and authorize, Git Hub will call back //yourappname and Safari will redirect it back to your app completing the flow.

iMessaged-based invitations for GameCenter for iOS 10

I'm trying to update my app to work correctly with the new features of GameCenter in iOS10.
I create a new GKGameSession on device1, get a share URL, and all that works fine. I send the share URL out via a share sheet to device 2.
Device2 clicks the link, the device briefly displays 'Retrieving...' and then launches my app. Great! But, now what? Is there context information available for this URL that I can somehow access? Otherwise I have no way how to respond when the app is launched.
Previously you'd get a callback to something adhering to the GKLocalPlayerListener protocol, to the method player:didAcceptInvite:, and you could join the match that way. But with these iCloud-based messages, the player might not be even logged into GameCenter, right? This part seems to have been glossed over in the WWDC presentation.
Also, as of today (12/28/2016) there is no Apple documentation on these new methods.
Since the GKGameSessionEventListener callback session:didAddPlayer: only fires if the game is already running, to be sure you can process this callback every time requires a work around. I've tested this and it works.
When you send out an iMessage or email invite to the game, don't include the Game Session Invite URL directly in the message. Instead use a registered URL that will open your app when opened on a device on which your app is installed. Check here to see how:
Complete Tutorial on iOS Custom URL Schemes
But add a percent escaped encoding of the game invite URL as a parameter to this URL thusly (I'm assuming the registration of a url e.g. newGameRequest but it will be best to make this quite unique, or even better - though it requires more setup, try Universal Link Support as this will allow you to direct users who don't have your app installed to a webpage with a download link)
let openOverWordForPlayerChallenge = "newGameRequest://?token="
gameState.gameSession?.getShareURL { (url, error) in
guard error == nil else { return }
// No opponent so we need to issue an invite
let encodedChallengeURL = url!.absoluteString.addingPercentEncoding(withAllowedCharacters:.urlHostAllowed)
let nestedURLString = openOverWordForPlayerChallenge + encodedChallengeURL!
let nestedURL = URL(string: nestedURLString)!
}
send the URL in a message or email or WhatsApp or whatever. Then in your app delegate, add the following:
func application(_ app: UIApplication, open url: URL, options: [UIApplicationOpenURLOptionsKey : Any] = [:]) -> Bool {
var success = false
if let queryString = url.query {
if let urlStringToken = queryString.removingPercentEncoding {
let token = "token="
let startIndex = urlStringToken.startIndex
let stringRange = startIndex..<urlStringToken.index(startIndex, offsetBy: token.characters.count)
let urlString = urlStringToken.replacingOccurrences(of: token, with: "", options: .literal, range: stringRange)
if let url = URL(string: urlString) {
if UIApplication.shared.canOpenURL(url) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
success = true
}
}
}
}
return success
}
Now you can be sure the session:didAddPlayer: will be called. What's the betting this workarround is good for about 2 weeks, and they fix this in the next release of iOS showcased at WWDC 2017 ! Update: this problem hasn't been fixed - so the workaround above remains good!
I agree, the lack of documentation is frustrating. From what I can see, we have to:
add <GKGameSessionEventListener> protocol in the class' header
Then session:didAddPlayer: fires on the joining player's device after accepting an invite link.
update:
Unfortunately, I'm not surprised to hear your results. I hadn't tried all of those scenarios, but GKTurnBasedMatch had similar shortcomings. The way I got around it there was: I added a list of player statuses to match data (invited, active, quit, etc). I gave the player a view of "pending invitations." When they opened that view, I would load all of their matches and display the entries where the player was in invited state. With GKGameSession, that should work too.
Or, it might be easier if you could maintain a local list of sessions that you are aware of. Whenever the game becomes active, pull the entire list of sessions from the server and look for a new entry. The new entry would have to be the match the player just accepted by clicking the share URL.

com.facebook.sdk.core error 8

This is more informative than anything. I couldn't for the life of me find anything on error code 8 when trying to access the login prompt (aka safari) when debugging my ios app. After I hit the log into facebook button in my app it would attempt to open safari then dump me back to the login page to my app. The error was being caused by the permissions array. I had the the permission "public_profile" spelled "public profile" which was throwing an error obviously. So make sure your permission are type corrected if you get the com.facebook.sdk.core error 8.
Hope that helps someone.
Make sure your permissions are typed correctly
func loginButton(loginButton: FBSDKLoginButton!, didCompleteWithResult result: FBSDKLoginManagerLoginResult!, error: NSError!) {
if error == nil {
println("login complete")
self.performSegueWithIdentifier("showLogin", sender: self)
}else{
println(error.localizedDescription)
//com.facebook.sdk.core error 8.
}
}
In my case this error was caused by improper bundle id set in facebook settings of the app itself. Facebook "bundle id" is case sensitive, in my Info.plist I had uppercase product name, but in fb settings - lowercase.
In my case, I was using a Facebook account that hadn't yet been added to any of the Facebook app's admins/developers/testers roles.
In my case, after spending several hours of debugging I found that I was using the API,
func application(application: UIApplication,
openURL url: NSURL, options: [String: AnyObject]) -> Bool {
if #available(iOS 9.0, *) {
FBSDKApplicationDelegate.sharedInstance().application(application, didFinishLaunchingWithOptions: options)
} else {
// Fallback on earlier versions
}
return true
}
which is deprecated for iOS 9.So, I used:
func application(application: UIApplication,
openURL url: NSURL, sourceApplication: String?, annotation: AnyObject) -> Bool {
FBSDKApplicationDelegate.sharedInstance().application(application, openURL: url, sourceApplication: sourceApplication, annotation: annotation)
return true
}
Which worked for me. Hope this saves time of someone.
MAN!!! In my case it was the "bio" in the parameter that was causing this error. Facebook has changed the "bio" key to "about". So anyone using "bio" in parameters should change it to "about"
Pheww!!!
In my case It was wrong version. Instead of version: "v2.7", I used version: "2.7"
In my case it was because I listed name twice in the fields array. Assume that would apply to any field requested twice.
I had the same problem. It was because I didn't implement facebook login feature. After adding that, I logged in and my problem got solved.
In my case, I was playing with the Facebook Ads API and I tried to get a field but the name was wrong.
I had insights{date_start,date_end}, instead of insights{date_start, date_stop}.
More info here.
Hope it helps anyone.
In my case, I tried to get Facebook Id without logging into Facebook. Make sure you're logged into Facebook.
let accessToken = FBSDKAccessToken.current()
if accessToken != nil {
self.getCurrentUserFbId()
print("LoggedIn")
} else {
print("Not loggedIn")
self.loginIntoFacebook()
}
Hope this will helpful for anyone.
When it happened to me, I found that Facebook's access token was expired. Someone decided to store access token in UserDefaults and reuse it later. Of course all tokens more than ~2 months old were expired.
In my case it was because of GraphRequest.
The error response is
"com.facebook.sdk:FBSDKErrorDeveloperMessageKey" = "Syntax error
\"Expected end of string instead of \"%\".\" at character 5:
email%2Cname%2Cgender%2Cpicture";
"com.facebook.sdk:FBSDKGraphRequestErrorCategoryKey" = 0;
"com.facebook.sdk:FBSDKGraphRequestErrorGraphErrorCode" = 2500;
"com.facebook.sdk:FBSDKGraphRequestErrorHTTPStatusCodeKey" = 400;
"com.facebook.sdk:FBSDKGraphRequestErrorParsedJSONResponseKey" = {
body = {
error = {
code = 2500;
"fbtrace_id" = AFEUYbcYP39;
message = "Syntax error \"Expected end of string instead of \"%\".\" at character 5: email%2Cname%2Cgender%2Cpicture";
type = OAuthException;
};
};
code = 400;
};
The issue about that is https://github.com/facebook/facebook-swift-sdk/issues/309
In my case was because of birthday,friendlists . removing them started to work.
For me just had to go facebook developer under platform and activate deep linking
In our case we were seeing this issue while trying to log in with some test account (but not all). We were not following Facebook's recommended practice:
Before you test each use case below, make sure you remove your app from your test user's Facebook account using app settings.
After we did it for the failing test accounts, we were able to log in.

LinkedIn open url company in iOS (URL Scheme)

I need to open in the LinkedIn app a company url from my iOS app in Swift. I have tried to do that with URL Scheme, but I haven't achieved it.
This code open the LinkedIn app, but not in the url I need:
UIApplication.sharedApplication().openURL(NSURL(string: "linkedin://profile/xxx_id_company_xxx")!)
Can anyone help me?
Swift 4
In your info.plist under LSApplicationQueriesSchemes add
<string>linkedin</string>, then in your code just add
let webURL = URL(string: "https://www.linkedin.com/in/yourName-yourLastName-yourID/")!
let appURL = URL(string: "linkedin://profile/yourName-yourLastName-yourID")!
if UIApplication.shared.canOpenURL(appURL) {
UIApplication.shared.open(appURL, options: [:], completionHandler: nil)
} else {
UIApplication.shared.open(webURL, options: [:], completionHandler: nil)
}
It seems the correct format is "linkedin://companyName/companyId"
See this SO question: How can open LinkedIn Comapny Url in iPhone app programmatically?
This linkedin company url scheme is working for me
linkedin://company?id={company-id}
This objective c code trys to open linkedin company page in linkedin app and fall backs to a modal webview presenting company web page.
/* try to open linkedin app with company url */
if (![[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"linkedin://company?id=2589010"]]) {
/* Unable to open linked app, present web page with url #"https://www.linkedin.com/company/sesli-sozluk" */
...
}
You can find your "company id" in the source code of your company page on linkedin. Search for "company-id" or "companyId", it is in a hidden input field.

Resources