iOS phone app: third party app integration like Viber/WhatsApp - ios

There is some API that allows third party apps to be display as an option in iOS native phone app:
As one can see there is Viber and WhatsApp, and by selecting it will open third party app.
which API is being used here? I've no clue what to search for in order get information how to integrate my voip app with native iPhone app. I suppose some kind of extension. any help on keywords to search for and any example are much appreciated.

Here is how to activate this option in native Apps:
First, one has to use CallKit framework. iOS will generate those options(called handles) automatically. The property responsible for that is supportedHandleTypes with CXHandleTypePhoneNumber handle type.
CXProviderConfiguration * config = [[CXProviderConfiguration alloc] initWithLocalizedName:NSLocalizedString(#"myAppName", #"")];
config.supportedHandleTypes = [NSSet setWithObjects:#(CXHandleTypePhoneNumber), nil];
The handle in native app will appear after this configuration is called. I've called this in my app delegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
If video handle should be appeared as well then configuration should be:
config.supportsVideo = YES;
There are two other handle types CXHandleTypeGeneric and CXHandleTypeEmailAddress, but I could not figure out what changes were caused by those handles. please do comment if you know what they do.
ps: I was using CXHandleTypeGeneric before, and I could not see handles for my App. As soon as I changed it to CXHandleTypePhoneNumber, the handle was added automatically in contact details.

Related

SFSafariViewController requesting to Open YouTube App when YouTube is installed

I have an iOS 9 only app which I am developing with a UITableViewController and a list of videos by a company. Some of the videos are hosted on YouTube. In the didSelectRowAtIndexPath, I implement the use of SFSafariViewController in the following way:
SFSafariViewController *safariVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:#"https://www.youtube.com/watch?v=YQHsXMglC9A"]entersReaderIfAvailable:NO];
safariVC.delegate = self;
[self presentViewController:safariVC animated:YES completion:nil];
Please note, the video in that link is not the video I am using for my app - it's simply an example.
When I click that without the YouTube.app installed on my device, it opens up in SFSafariViewController. If I have YouTube.app installed, it prompts me to open the link in there:
I understand why this is happening, because of the work in iOS 9, but how can I prevent it? It'll be pretty annoying for my users to have to go to YouTube to watch the video and then come back to the app (even if it's via the back link at the top).
How can I prevent this from happening within the app, to say use the SFSafariViewController within the app rather than the YouTube app?
Update
This behaviour does not happen with the Twitter or Facebook native apps, so the question is, is this a YouTube native app issue (something I can't do anything about) or is there a way for me to prevent the opening? With SFSafariViewController, Apple's aim would have been to make it easier; there must be a way to prevent apps from prompting and loading in the native app.
Any guidance on this would be appreciated.
I don't see a delegate to do this. I guess this is the native behavior and exactly what you get with a SFSafariViewController. You COULD recreate a 'light version' by using a WebView directly instead

iOS - Return to Safari from Native App without Opening New Tab

I am having trouble figuring out how to switch to Safari from a native app in iOS 7+. I've used UIApplication.sharedApplication.openURL(), but that opens a new tab. I would like to return the user to the current page he/she was viewing before without opening a new tab. I found this SO post, but it is a few years old, so I was hoping things have changed since then.
Here is the workflow I am envisioning:
User taps on a link on an HTML page on Safari to open/install my app
User performs an action on my app
After the user is done performing the action, my app opens Safari automatically, and the user is back on the page where he/she left off
Google has somehow done this with their Google Maps app. If you search for an address on google.com on Safari, you can tap on the map that appears in the search results, and it will open the Maps app. At the top of the Maps app will be a "Return to Safari" bar that you can tap. Once you tap it, you are returned to Safari without loading another tab. I can't seem to find anything regarding how Google did this. If I can replicate that behavior in my app, that would work just fine.
Any help would be greatly appreciated!
There is a way to accomplish what you want using standard iOS APIs. No need to use external components.
You control your webpage and your app, so you know the exact URL that has the link to your app.
These are the steps:
1) In your app, define a custom URL scheme. In this case let's assume you use the scheme myawesomeapp://. You can do this in your Xcode project by going to the Info section of your target. See below
2) In your web page you need to handle the two scenarios: app installed / not installed. It is just a matter of detecting if an app responds to the scheme myawesomeapp://.
To detect from your webpage if your app is not installed please refer to this post
I will explain the case where your app is already installed.
Let's say the webpage that contains the link is:
http://www.mywebsite.com/mypage.html#mytag
The link you provide in your webpage should pass some parameters to the app and one of these should be the URL that you want the app to return. Following with the example the link could be:
myawesomeapp://?action=my_action_1&sourceurl=http%3A%2F%2Fwww.mywebsite.com%2Fmypage.html%23mytag
Note that the URL you pass as a parameter inside the scheme has to be URL encoded or it won't work properly.
3) In your app delegate you need to implement the method:
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(NSString *)sourceApplication annotation:(id)annotation
In this method, parse the URL, decode the query items and pass the sourceURL to the view controller responsible of handling the action prior to calling it. In this case I set a public property in the ViewController that will store the URL.
#property (nonatomic, strong) NSURL *sourceURL;
4) In the view controller when the user finishes the interaction, you just call:
[[UIApplication sharedApplication] openURL:self.sourceURL];
Because self.sourceURL contains the URL of your webpage, Safari will be launched with the URL. However, because that page is already opened, iOS detects this and re-opens that page.
I have a sample project in my Github page that implements all this.
And to finalize, after you install the sample project in your iPhone, open this stack overflow post from mobile Safari and open my awesome app
Once the app is opened, click on the button and you will return to this stack overflow post.
The behaviour you described is exactly what FB's AppLinks is designed for, and you'll get the same behaviour with all iOS apps that support it (which is quite a lot) out of box!
By the way Google Maps uses the same component: you can see it if you open Google Maps from let's say Fantastical.app!

Discover all end points supported by UIActivityViewController like WeChat, KaKao, Line, and others?

This SO post addresses how to customize the UIActivityViewController by excluding services like AirDrop or printing.
It also mentions this Apple doc which highlights the stock services supported, but how do we identify other supported end points like Line and other messaging apps?
Specifically:
(1) Do Skype, Kakao, Line, Viber, WeChat, Kik, WhatsApp, and Facebook Messenger (not Facebook proper) have end points?
(2) What are those end points?
You can't do that currently on iOS 7, because no application can talk directly to other applications yet for security reasons. One of the highlights of the last WWDC was the introduction of extensions for iOS 8, which will make this possible; you can read how in the Creating Action Extensions example.
There are however attempts at fixing this. A notable example is IntentKit, which works by having a repository of known apps.
What is IntentKit?
IntentKit is an open-source iOS library that makes it easier to link to other apps. It's sort of like Android's Intents or Windows Phone's Contracts.
Another example of one of such attempts is OvershareKit
Why OvershareKit?
Sharing is far too cumbersome to implement on iOS. UIActivityViewController is too limiting, and rolling your own library is too time-consuming. Most devs end up settling for underwhelming sharing options for lack of the time or inclination to make something better.
OvershareKit makes it trivial to add rich sharing options to your iOS apps.
How to know if an application is installed?
Even though you can't discover them. If you know the application you're looking for and what kind of URL Scheme it responds to, then you can check if your app is able to open that kind of URL.
That's what IntentKit is for, it's a repository of knowledge about applications, the URL Schemes they respond to and the kind of actions they can perform. With the introduction of extensions.
For example, you can check if Facebook is installed by checking if you can open a fb:// URL.
BOOL isFacebookInstalled = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"fb://"]];
About IntentKit's inner workings
Internally, IntentKit will check for that same thing, as you can see in INKActivity's implementation:
- (BOOL)canPerformCommand:(NSString *)command {
if (!self.actions[command]) { return NO; }
if (self.presenter) {
return [self.presenter canPerformAction:command];
} else {
NSURL *url = [NSURL URLWithString:[self.actions[command] urlScheme]];
return [self.application canOpenURL:url];
}
}
Info about requested UIActivity services:
Skype uses the "skype:" URI, more info in the official documentation
Kakao & Line, with DCActivity (there seems to be an official API for Kakao, but the documentation is in korean)
Line, with LINEActivity
WeChat, with WeixinActivity (there's also an official API with which you can make your own UIActivity)
WhatsApp uses the "whatsapp:" URI, more info on the official FAQ, there are also various UIActivity implementations for WhatsApp, take a look at them in cocoapods.com
Facebook Messenger uses the "fb-messenger:" URI, more info in this other answer by tia, also see workarounds.
Kik has a public API, but no SDK nor UIActivity implementation that I know of. Also, see workarounds.
Viber has no SDK nor public API, see workarounds.
Workarounds
Most of these services are based on known protocols, or slight variations of them. For example, you can use XMPP (aka Jabber) to directly send messages to a Facebook IM or Kik account; some people say that Viber seems to use a modification of SIP for signaling with VoIP phones. So you could work around some SDK/API limitations by using the underlying mechanisms.
SDK or API?
If all you need is to send a message to those services, I'd argue that you don't really need to communicate with the installed application via an SDK or URL Schemes, I haven't been able to test the Big Emoji app you mentioned, as it just crashes on iOS 8, but if it's using the services API's, you could easily work it out by using Charles or Wireshark.
Presumably they are adding a bunch of their own custom actions, as described in this answer.
There is no central repository for third-party sharing support before iOS 8. You can check for the other apps' presence by using URL Schemes. To do this, you'll have to look at each app's documentation and figure out what schemes they accept, then do something like this:
NSArray* items = /* stuff you want to share */
NSMutableArray* activities = NSMutableArray.array;
if ([UIApplication.sharedApplication canOpenUrl:#"whatsapp://url"])
{
UIActivity* activity = /* create activity for whatsapp */
[activities addObject:activity];
}
if ([UIApplication.sharedApplication canOpenUrl:#"facebook://url"])
{
UIActivity* activity = /* create activity for facebook */
[activities addObject:activity];
}
// ... repeat for other services ...
UIActivityViewController *activityVC = [[UIActivityViewController alloc] initWithActivityItems:items applicationActivities:activities];
// show the VC however appropriate.
In addition to #NinoScript, you can find here the URL schemes for the iOS apps (inside the .plist files) which is provided by IntentKit as he mentioned.
Here is a summarized list from the project:
1Password ophttps://{{{url}}}
Chrome: googlechromes://{{{url}}}
Gmail: googlegmail:///co?to={{recipient}}
Google Maps: comgooglemaps://?q={{query}}
Google+: gplus://plus.google.com/{{userId}}
Safari: http://{{{url}}}
For a full URL-schemes search the git project.

Where exactly should I put the call to [FBSettings publishInstall:appId]

I'm looking at integrating support for tracking Facebook's new mobile app ads.
I've read the tutorial here:
https://developers.facebook.com/docs/tutorials/mobile-app-ads/
It says:
Include the following code to be executed when your app opens for the first time by user
[FBSettings publishInstall:appId];
So the first question is - where do I put this so that it only invokes the call if the install was driven from Facebook? I don't want FB to get credit for someone who found my app themselves on the app store.
Do I need to manually track whether or not I've called the publishInstall before for this specific user? (The preamble sentence implies this - but the SDK documentation for publishInstall implies otherwise).
And even more confusing is that the SDK FBSettings reference includes shouldAutoPublishInstall which defaults to YES. This would suggest that I don't need to do anything other than have the SDK integrated. So why does the tutorial not mention this as an option?
I assume that the appId is the associated Facebook appId (as opposed to the App Store App ID). This is also not clear from the documentation.
I browsed the sources of facebook iOS SDK, and it seems that guide is wrong.
You are right, that autoPublishInstall is set to YES by default, which means we don't need to invoke [FBSettings publishInstall:appId]; manually. AppId is indeed the facebook app id.
When you invoke openActiveSessionWith.... method, it initializes FBSession with
initWithAppID:permissions:defaultAudience:urlSchemeSuffix:tokenCacheStrategy: which contains in the end [FBSettings autoPublishInstall:self.appID];
+ (void)autoPublishInstall:(NSString *)appID {
if ([FBSettings shouldAutoPublishInstall]) {
dispatch_once(&g_publishInstallOnceToken, ^{
// dispatch_once is great, but not re-entrant. Inside publishInstall we use FBRequest, which will
// cause this function to get invoked a second time. By scheduling the work, we can sidestep the problem.
[[FBSettings class] performSelector:#selector(publishInstall:) withObject:appID afterDelay:FBPublishDelay];
});
}
}
So technically it should report the install out of the box (if I'm not missing something). I'm going to play with it a little more today to see if it works as expected and update answer with results.
Just put it at -[application:didFinishLaunchingWithOptions].
Not all of the apps want to integrate the Facebook login. They only want the feature "mobile app install ads". For these kind of app, they should invoke +[FBSettings publishInstall:appId] manually. On the other hand, if your app has already integrated facebook login, you can assume that the FB sdk has published the installation.
If we just have to put
[FBSettings publishInstall:appId];
manually in
-[application:didFinishLaunchingWithOptions]
how will I identify which install happened from facebook? I don't want FB to get credit for someone who found my app themselves on the app store.
put the code in Appdelegate DidbecomeActive method
- (void)applicationDidBecomeActive:(UIApplication *)application
hope this help :)

iOS: How to Have an Application Launched with [UIApplication sharedApplication] from My App Return Control Back To My App

Right now I'm able to launch something like the mail app with this call:
NSURL* mailURL = [NSURL URLWithString: #"emailAddress#example.com?cc=&subject=Feedback"];
[[UIApplication sharedApplication] openURL: mailURL];
However, what I'd like is for mail to return control back to my app automatically once the user finishes sending an email. Is this possible?
This is not possible at the moment.
There has been a bit of an effort to try and get apps to accept a url callback parameter that would indicate which app control should be returned to.
See http://x-callback-url.com/
The goal of the x-callback-url specification is to provide a standardized means for iOS developers to expose and document the methods they make available to other apps. Using x-callback-url’s source apps can launch other apps passing data and context information, and also provide parameters instructing the target app to return data and control back to the source app after executing an action. Specific supported actions will be dependent on the individual apps and will not be discussed in the specification.
but obviously without an 'official' solution you'd never get control back from mail.app.
I've written up the various strategies for integrating iOS applications in some detail today. It sounds like MFMailComposeView is all you need, but in case anyone else comes to read this question on more general integration grounds:
http://blog.codiform.com/2011/04/integrating-applications-in-ios-and-x.html
X-callback-url is definitely the promising (but relatively new) entrant to the return-to-caller model you'd otherwise need.

Resources