My app generates some sort of text information.
User presses button like "Share" in my app and after that pops up a windows with a list of installed applications or only apps which can recieve string parameter. After that, user selects, for example, "Mail" app and then it is opened with the new email message and with a given text from my app. Or user selects Skype app and then it is opened with a given text.
How could those scenarios be implemented in iOS?
PS: I already saw similar behavior in Android app (via Intent extras).
UPDATE: I posted the answer below that works for me (via UIActivityViewController) exactly how I need.
There is no single answer that will work for all target apps. You need to research each app and see if it has a facility for receiving info from other apps.
A simple way to do this is to invoke an URL that targets the other app.
For mail, you could invoke a mailto:// URL that composes an email with the text in the desired field(s) (to, cc, bcc, subject, or body.)
If the app supports the iOS document model you may be able to pass it a document to open.
If the target app has a server then you may also be able to connect to the server and send data to it that way. Again, this is not a question you can ask in general. The answer will be different for each target app, and for some apps the answer will be "you can't, because it doesn't have any mechanism to receive data from an outside app."
Android is a different beast with different abilities than iOS. iOS is more of a "walled garden", with very limited access outside of your app.
I found the best solution for me is
- (IBAction)onShare:(id)sender {
NSString *textStr = self.textToShare.text;
NSArray *items = #[textStr];
UIActivityViewController *activity = [[UIActivityViewController alloc]
initWithActivityItems:items
applicationActivities:nil];
[self presentViewController:activity animated:YES completion:nil];
}
It does exactly what I need. It shows popup view with the list of apps which are able to receive text string. Then user can select any of them and controller sends text to it.
Related
Suppose I'm making an app that a user can install several little interactive experiences (meditations) onto.
For convenience, I'd like my users to be able to start one by saying: “Hey Siri, start Beach Sunset in Meditations.”
Because of reasons, it makes sense for users to perform this action by voice, without ever first having interacted with Beach Sunset in the iOS app. (They may for example already “own” it through my service's web app.)
That is to say: I want a voice action like “Hey Siri, start Beach Sunset in Meditations” to work even without the user setting up a Shortcut for it first, or me “donating” actions for it.
Is that possible? (I feel like many of the default apps expose similar behavior, but maybe they're special.) If not, what is the next best thing I can do?
Are "donations" necessary for Siri to be aware of my app's voice actions, or are they simply a mechanism for hinting and predicting user behavior?
Are "shortcuts" necessary for Siri to be aware of my app's voice actions, or are they simply a mechanism for user phrase customization?
I've never added Siri support to an iOS app, but it seems “parameters” have gotten a lot more powerful in iOS 13. This answer suggests something similar wasn't possible in iOS 12, but I think it's also doing something somewhat different (I want to launch the app; they want to “create an object” presumably just using Intent UI. I don't know if this matters.)
What I've done
I've defined a custom intent in the Start category (LaunchMeditation) with a single parameter (meditationName).
I considered the standard Media intents, but the media here is interactive and not strictly audio/video, and I don't want to get in trouble.
I've added an Intents Extension to my app, and written a rudimentary test "handler" that just tries to pass the meditation name on to the app:
#interface IntentHandler () <LaunchMeditationIntentHandling>
#end
#implementation IntentHandler
- (id)handlerForIntent:(INIntent *)intent { return self; }
- (void)handleLaunchMeditation:(nonnull LaunchMeditationIntent *)intent
completion:(nonnull void (^)(LaunchMeditationIntentResponse * _Nonnull))completion {
// XXX: Maybe activity can just be nil?
NSUserActivity *activity = [[NSUserActivity alloc] initWithActivityType:#"com.example.meditations.activity.launch"];
activity.title = [NSString stringWithFormat:#"Launch %# in Meditations", intent.meditationName]; // Do I need this?
activity.userInfo = #{#"meditationName": intent.meditationName};
completion([[LaunchMeditationIntentResponse alloc] initWithCode:LaunchMeditationIntentResponseCodeContinueInApp
userActivity:activity]);
}
- (void)resolveMeditationNameForLaunchMeditation:(nonnull LaunchMeditationIntent *)intent
withCompletion:(nonnull void (^)(INStringResolutionResult * _Nonnull))completion {
completion([INStringResolutionResult successWithResolvedString:intent.meditationName]);
}
#end
When I test the Intents Extension, I can now make a Shortcut for it in Shortcuts, set its parameter, give it a name (like “Beach time”), and launch it by telling Siri that name — which is everything I don't want users to have to do.
Other than that, Siri responds with
Meditations hasn't added support for that with Siri.
…no matter how I phrase my request to start Beach Sunset. That “hasn't added support” sounds agonizingly much like there's simply something I'm missing.
I'll try to briefly answer all of your questions.
You can't create a Siri action without donating actions. Once you donate your actions they are not registered to Siri either. Users must create a Shortcut to be able to use them.
The next best thing you can do is to inform your users about your Siri Shortcuts. To do this you can show a pop-up or inform your new users on onboarding screens. The good part is you can redirect your users to the "Creating Siri Shortcut" screen via this code which you can trigger by button click or tap gesture.
let shortcut = INShortcut(userActivity: shortcutActivity!) // shortcutActivity is your donated activity.
let vc = INUIAddVoiceShortcutViewController(shortcut: shortcut)
vc.delegate = self // INUIAddVoiceShortcutViewControllerDelegate
self.present(vc, animated: true, completion: nil)
Shortcuts are necessary for Siri to be aware of you implementation.
As far as I know intent domains help you specify more parameters for your Siri shortcuts. Which enables you to create more Siri interactions.
Apple also promotes Siri Shortcuts of commonly used apps. If your users are using your app in a regular basis or more often than others they might see a Siri Shortcut Suggestion in their home screen. Similar to this one.
I also think it would be great to donate Siri Shortcuts without any user action but there would be certain problems such as:
What if two or more different apps uses the same phrase for a Siri Shortcut?
How will Siri distinguish an unregistered command from a simple conversation? For example if someone created a shortcut with the phrase "Hi Siri".
Even if you donate an action with a certain phrase Siri must learn how it's user pronounces that certain phrase.
These may cause a lot of harm than good thus I think Apple choose the current way. Hope these answers your questions.
I checked the latest Dropbox and Excel for iOS. In Dropbox we get an edit button. On click it opens Excel's extension where you can edit the file.
After save, changes are reflected in the Dropbox file too.
I want to add such a button. Also I'd like to add such a button to images to open them in available "photo editing" apps.
How to check if file (image, xls, doc or any other) can be opened to edit?
Code so far:
UIDocumentPickerViewController *documentPicker = [[UIDocumentPickerViewController alloc] initWithURL:url inMode:UIDocumentPickerModeExportToService];
documentPicker.delegate = self;
documentPicker.modalPresentationStyle = UIModalPresentationFormSheet;
[self presentViewController:documentPicker animated:YES completion:nil];
Also tried changing mode to UIDocumentPickerModeMoveToService...
As per apple docs
Move a local document. The user selects an external destination. The document picker moves the document; however, you can still access the document as an external document, letting the user edit the document in place.
But I tried all four modes. Did not show excel option.
UIDocumentPickerModeImport,
UIDocumentPickerModeOpen,
UIDocumentPickerModeExportToService,
UIDocumentPickerModeMoveToService
The only way to communicate with other iOS apps "locally" is using what is called URLSchemes.
This is the documentation to use URLScheme with the MSOffice apps.
https://msdn.microsoft.com/en-us/library/office/dn911482.aspx
Answering the specific question:
How to check if file (image, xls, doc or any other) can be opened to edit?
You can use the UIApplication method called canOpenURL to check if the current device responds to a specific URLScheme and if it does, you can call the app to edit you file. The same can be applied to other apps that you want to open. You just need to see if the app have URLScheme support.
Remembering that in iOS 9 you need to add the URLs you want to call during the app life in the Info.plist. Otherwise, the canOpenURL method will always returno NO.
This code illustrates the approach. However, it is to search some navigation apps. Just like tapping a shared friend location in WhatsApp.
https://snipt.net/wallaaa/using-url-schemes/
The result:
it's 2017 and iOS 11 and it's still not possible to edit files in place.
Dropbox is using MS Office API to provide http links to download and upload changed document.
Direct edit of the file is only possible if FileProvider extension is implemented and file was opened in editor app via document picker (which grants access to the file in sandbox).
Photo editing is allowed because editor is made by Apple (Photos app).
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.
Is there any way i can prefill any string in FBWebDialog? Any workaround would do,I am aware facebook has deprecated the message parameter from their sdk.
My scenario is user clicks on a facebook contact
FBWebDialog opens and then the message gets prefilled with some text instead of a blank textfield.
any help would be appreciated
Thanks
Okay, from the comments it sounds like you want to post on the user's wall. Here is a method that is available in the FB SDK that pulls up a share dialog within your app and supports pre filled text
[FBDialogs presentOSIntegratedShareDialogModallyFrom:self initialText:#"Initial text" image:nil url:nil handler:nil];
Example with pre filled text:
Which type of dialog are you opening? (Sounds like the Send dialog, if you want to send a Facebook message.)
I do not think it is possible to even send a message directly to a user from iOS. When performing the following I get the error "This dialog is not available on this device"
[FBWebDialogs presentDialogModallyWithSession:nil dialog:#"send" parameters ...
iOS FB SDK WebDialog reference shows the following methods:
+ presentRequestsDialogModallyWithSession:message:title:parameters:handler:
+ presentRequestsDialogModallyWithSession:message:title:parameters:handler:friendCache:
Those seem to support pre-populating the message field. They only support apprequests though (not messages) and whether the message is even attached is a bit unknown (all I saw when testing was "User wants you to try App", not the actual string I set).
The javascript API (which could maybe be pulled up in a webview?) doesn't have a parameter to set the message probably because the Send dialog documentation says:
Facebook messages are a channel for person-to-person communication,
and not for apps to send messages, or encourage people to spam their
friends.
If you just want to post a message/share then you can use a share sheet which looks to support an initial message:
[FBNativeDialogs presentShareDialogModallyFrom:self initialText:#"My text to share" ...
Here are my requirements:
1. Create links to a single app in the app store 2. Access the links either from inside an app, on the device generally (e.g. mail link) or from a PC (e.g. via facebook share link) 3. Open links using iPhone or iPad running iOS 5+
I have done some digging around and come up with the following options:
http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=487547243
http://itunes.apple.com/gb/app/anyValue/id487547243?mt=8
http://itunes.com/apps/seligmanVenturesLtd/mouseTrapFree
http://itunes.com/apps/mouseTrapFree
itms://itunes.com/apps/mouseTrapFree
itms-apps://itunes.com/apps/mouseTrapFree
Just wondering if one (or some) of these are better than other?
Thanks.
Ok, so have done a lot of research/testing and here is my conclusion:
Links you use in your code should not rely on the 'current' name of you app, since this might change over time (e.g. Light Alarm Lite vs Light Alarm Free). Therefore the following 4 are out IMHO:
http://itunes.com/apps/seligmanVenturesLtd/mouseTrapFree
http://itunes.com/apps/mouseTrapFree
itms://itunes.com/apps/mouseTrapFree
itms-apps://itunes.com/apps/mouseTrapFree
That leaves itunes and phobos URLs. I have just tested both URLs via the iOS 6 share functionality (so this might be different on iOS 5, but given numbers are reducing daily for that I dont really mind). I tested accessing via SMS, Email, Facebook, Twitter (on an iPhone 5 and using a Mac).
Both url types produced near identical results, except for the following:
Phobos:
e.g. http://phobos.apple.com/WebObjects/MZStore.woa/wa/viewSoftware?id=346542660
+ None
- Sharing this link on facebook created a facebook link without any image... this was the showstopper for me that will mean I use iTunes urls going forward (see below).
iTunes
e.g. http://itunes.apple.com/gb/app/appName/id346542660?mt=8
+ When opening link on iphone 'Mail' app the app store opened within the 'Mail' app and no tabs along the bottom appeared, so arguably this creates increased focus on your app
- None
In summary, I will be going with itunes type urls going forward. eg:
e.g. http://itunes.apple.com/gb/app/appName/id346542660?mt=8
(Note: you don't have to stipulate the '/appName' in this url, just keeping it as '/appName/' works fine, which means you dont have to worry if you app name changes over time.
Cheers, Charlie
URL/Link to an app on the app store can be created very easily but there are several ways to achieve the end result. First of all we need to be clear on the purpose of the link (For ex. link might be used for Facebook posts or used inside an app for urging users to rate the app through in-app alerts/buttons). We can broadly categorize how we will use the link in 3 categories:
1. We want to use the link publicly outside the iOS (or OS X) domain. Means you can use this link to share on your Facebook wall or you want to embed the link in mail. I said outside iOS domain because your friends who doesn't have iPhone (or any other iOS device) or MacBook they might also use click that link from Facebook or their mail app/client.
2. We want to use the link inside iOS (or OS X) domain. Means when we are certain that our link will be clicked by device using iOS or OS X.
3. We want to send the app user (already a user of our app) to specific section (like review section) of the app on app store.
For category 1 and 2 it's best to use this type of URL:
https://itunes.apple.com/app/dots-a-game-about-connecting/id632285588?mt=8
When you embed this link then it can result in several outcomes:
If user clicks on this link from iPhone (from any iPhone app or mail app on iPhone): Your app page on App Store will open directly
If user clicks on this link from any Android Phone or Browser (Chrome/Safari/etc.): Your app page on itunes.apple.com website will open inside default browser. Even if you are opening it on you MacBook it won't open iTunes App Store but will display you app page in Browser itself.
Side Note: There are several places on web where below mentioned sort of link is also suggested:
http://appstore.com/dotsagameaboutconnecting
When you embed this link then it can result in several outcomes:
If user clicks on this link from iPhone or MacBook: Your app page on App Store will open directly. So this link is a bit better for MacBook users as it send users of MacBook directly to iTunes instead of staying within Safari browser.
If user clicks on this link from any Android Phone or Browser (Chrome/Safari/etc.): If user is clicking from PC that has iTunes installed then this link will open your app on iTunes else (on Android devices and PC that doesn't have iTunes) it will open a Apple.com page displaying "Download iTunes" without any mention of your app. Screenshot of that page below:
So If you are not sure about who will click on your link (outside/inside iOS domain) or If you want to be on safer side then I recommend first approach. Read here on how to create specific link for your app.
For category 3 simply use below code in some function/action:
NSString *myAppID = #"632285588";
NSString *url = [NSString stringWithFormat: #"itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=%#", myAppID];
//iOS7 doesn't approve above format so add iOS7 specific format
if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
url = [NSString stringWithFormat: #"itms-apps://itunes.apple.com/app/id%#", myAppID];
}
[[UIApplication sharedApplication] openURL: [NSURL URLWithString: url]];
For details on above code see this answer.
For developers who are developing first version of app and app is still not published on app store there is always a quandary about how to get the right link for your to be published app. For that:
Get your app ID from iTunesConnect. Use iTunesConnect to create your new app - give it a name, description, icon, screenshots, etc. Once app is created on iTunesConnect (without even submitting the app), you can get the Apple ID from the Identifiers section for the app.
You should not have any problems with the following one:
http://itunes.apple.com/gb/app/notebookpro/id<APP_ID>?mt=8
I believe, it will be opened on all major browsers/OS.
https://itunes.apple.com/app/id##app-id##?mt=8
Replace ##app-id## with real app-id.
For example:
https://itunes.apple.com/app/id346542660?mt=8
Summary
No country code. Ex: gb
No appName, only app-id.
https protocol.
I'm using the itms-apps: approach in our app, which also allows you to select to which "section" of your app the user will land.
So if you want to show them the reviews, this is what I use: itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewContentsUserReviews?type=Purple+Software&id=XXXXXXX
and for updating to the latest version of our app: itms-apps://ax.itunes.apple.com/WebObjects/MZStore.woa/wa/viewSoftwareUpdate?id=XXXXXXX&mt=8