I see other live app can open host app when use control center record.
[self.extensionContext openURL:YOUR_NSURL completionHandler:nil];
or
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:[NSString stringWithFormat:#"myapp://"]]];
or
func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
is doesn't work.any one know this?
Thank you for you time.best wishes
I'm getting "Incoming audio call" however the call is Video
Hint: I'm using (IOS SDK 3.10.1) SDK and SinchService.
here is the code:
func startVideoCall(userId: String, isPrivate: Bool) -> SINCall? {
if let user = User.current {
let callingId = userId
if let callClient = self.callClient() {
let privateString = isPrivate ? VoipCallConstants.Parameters.PrivateTrue : VoipCallConstants.Parameters.PrivateFalse
let headers:[String: String] = [VoipCallConstants.Parameters.Private:privateString]
let call = callClient.callUserVideo(withId: callingId, headers: headers)
return call
}
}
return nil
}
func callClient() -> SINCallClient? {
let appDelegate: AppDelegate = (UIApplication.shared.delegate as! AppDelegate)
return appDelegate.sinch?.callClient()
}
class AppDelegate: UIResponder, UIApplicationDelegate{
var sinch: SINService!
var push: SINManagedPush!
}
and i added in SINSLazyCallClient this
- (id<SINCall>)callUserVideoWithId:(NSString *)userId {
return [self callUserVideoWithId:userId headers:#{}];
}
- (id<SINCall>)callUserVideoWithId:(NSString *)userId headers:(NSDictionary *)headers {
if (self.proxee) {
return [self.proxee callUserVideoWithId:userId headers:headers];
} else {
return [[SINSFailedCall alloc] initWithUserId:userId headers:headers];
}
}
here is Localization.strings
SIN_INCOMING_CALL = "Incoming audio call";
SIN_INCOMING_CALL_DISPLAY_NAME = "Incoming audio call from %#";
SIN_INCOMING_VIDEO_CALL = "Incoming video call";
SIN_INCOMING_VIDEO_CALL_DISPLAY_NAME = "Incoming video call from %#";
Thanks for your feedback. We looked into this and it turned out the support for SIN_INCOMING_VIDEO_CALL and SIN_INCOMING_VIDEO_CALL_DISPLAY_NAME is not implemented in our system yet. We will keep you updated once this is fixed.
I am new to iOS. I want to integrate Skype in my iPhone application,for this I have searched lot but I have not found a solution for this
How can I get Skype SDK for integration. How can I integrate Skype API in my application. Is there any other way to make developer Skype account
If your people having any sample code please post that.Please help me. Many Thanks.
I have tried some code please see that below but using that code my simulator it's showing alert like below image
my code:-
- (IBAction)skypeMe:(id)sender {
BOOL installed = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"skype:"]];
if(installed)
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"skype:echo123?call"]];
}
else
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"http://itunes.com/apps/skype/skype"]];
}
}
For Swift 3.0 It opens itunes url if it is not installed, otherwise it will open skype.
#IBAction func btnSkypeLinkPressed(_ sender : UIButton) {
let installed = UIApplication.shared.canOpenURL(NSURL(string: "skype:")! as URL)
if installed {
UIApplication.shared.openURL(NSURL(string: "skype:skypeID")! as URL)
} else {
UIApplication.shared.openURL(NSURL(string: "https://itunes.apple.com/in/app/skype/id304878510?mt=8")! as URL)
}
}
and in plist add:
<key>LSApplicationQueriesSchemes</key>
<array>
<string>skype</string>
</array>
Hope it will work for swift users Thanks.
Here is your swift code:
Swift
#IBAction func skypeMe(sender: AnyObject) {
let installed = UIApplication.sharedApplication().canOpenURL(NSURL(string: "skype:")!)
if installed {
UIApplication.sharedApplication().openURL(NSURL(string: "skype:echo123?call")!)
} else {
UIApplication.sharedApplication().openURL(NSURL(string: "https://itunes.apple.com/in/app/skype/id304878510?mt=8")!)
}
}
Objective-C
- (IBAction)skypeMe:(id)sender {
BOOL installed = [[UIApplication sharedApplication] canOpenURL:[NSURL URLWithString:#"skype:"]];
if(installed){
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"skype:echo123?call"]];
} else {
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"https://itunes.apple.com/in/app/skype/id304878510?mt=8"]];
}
}
I have changed skype URL for iTunes in this code and tested it with device and both URL is working fine.
in addition to #Dharmesh's answer, in iOS9 you must add the application you want to query for 'canOpenUrl' to you plist, under LSApplicationQueriesSchemes key
see this answer: https://stackoverflow.com/a/30988328/1787109
Using Swift 5 you can integrate "one to one" call and also one to many call in skype
#IBAction func btnStartSkypeCall(_ sender: UIButton) {
var installed: Bool? = nil
if let url = URL(string: "skype:") {
installed = UIApplication.shared.canOpenURL(url)
}
if installed ?? false {
if self.mainModelView.eventList!.students?.count ?? 0 <= 1{
if let url = URL(string: "skype:SkypeID?call&video=true") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}else if self.mainModelView.eventList!.students?.count ?? 0 > 1{
if let url = URL(string: "skype:test_skype;test2_skype;test3_skype?call&video=true") {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}else{
print("Student list is empty")
}
} else {
if let url = URL(string: "https://itunes.apple.com/in/app/skype/id304878510?mt=8") {
UIApplication.shared.open(URL(string:"\(url)")!)
}
}
}
To start a chat use the schema
skype:user?chat
To start a video call use
skype:user?call&video=true
You must be add in plist file
<key>LSApplicationQueriesSchemes</key>
<array>
<string>skype</string>
</array>
I'm trying to send an email from my app. But what I want is if user is having Gmail app on his/her phone, then mail should be sent using it. If Gmail app is unavailable then the user should be redirected to Mailbox.
So how can I know if user contains Gmail app and how can I redirect user to it.
Setup for iOS9+
As explained here, if you're on iOS9+, don't forget to add googlegmail to LSApplicationQueriesSchemes on your info.plist
Code to open GMail
Then, you can do the same as the accepted answer (below is my swift 2.3 version):
let googleUrlString = "googlegmail:///co?subject=Hello&body=Hi"
if let googleUrl = NSURL(string: googleUrlString) {
// show alert to choose app
if UIApplication.sharedApplication().canOpenURL(googleUrl) {
if #available(iOS 10.0, *) {
UIApplication.sharedApplication().openURL(googleUrl, options: [:], completionHandler: nil)
} else {
UIApplication.sharedApplication().openURL(googleUrl)
}
}
}
You need to use custom URL Scheme. For gmail application its:
googlegmail://
If you want to compose a message there you can add more parameters to this URL:
co?subject=Example&body=ExampleBody
You can determinate if any kind of application is installed using this code (just replace customURL obviously for an other apps):
NSString *customURL = #"googlegmail://";
if ([[UIApplication sharedApplication]
canOpenURL:[NSURL URLWithString:customURL]])
{
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:customURL]];
}
else
{
//not installed, show popup for a user or an error
}
For Swift 3.0+
Notes:
This solution shows how to use spaces or newlines in the arguments to the URL (Gmail may not respect the newlines).
It is NOT necessary to register with LSApplicationQueriesSchemes as long as you don't call canOpenURL(url). Just try and use the completion handler to determine if it succeeded.
let googleUrlString = "googlegmail:///co?to=\(address.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")&subject=\(subject.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")&body=\(buildInfo.addingPercentEncoding(withAllowedCharacters: .alphanumerics) ?? "")"
if let googleUrl = URL(string: googleUrlString) {
UIApplication.shared.open(googleUrl, options: [:]) {
success in
if !success {
// Notify user or handle failure as appropriate
}
}
}
else {
print("Could not get URL from string")
}
I couldn't figure out why this wasn't working for me until I realised I was targetting a info_development.plist instead of the production-file info.plist
If you're like me and happen to have multiple Plists (one for development, one for prod etc) make sure you edit it everywhere. ;-)
Swift 5
These answers can open gmail but what if the user do not have gmail installed in the device? In that case I have handled opening apple mail/outlook/yahoo/spark. If none of them are present, I am showing an alert.
#IBAction func openmailAction() {
if let googleUrl = NSURL(string: "googlegmail://") {
openMail(googleUrl)
} else if let mailURL = NSURL(string: "message://") {
openMail(mailURL)
} else if let outlookURL = NSURL(string: "ms-outlook://") {
openMail(outlookURL)
} else if let yahooURL = NSURL(string: "ymail://") {
openMail(yahooURL)
} else if let sparkUrl = NSURL(string: "readdle-spark://") {
openMail(sparkUrl)
} else {
// showAlert
}
}
func openMail(_ url: NSURL) {
if UIApplication.shared.canOpenURL(url as URL) {
UIApplication.shared.open(url as URL, options: [:], completionHandler: nil)
}
}
You might also may have to add this in the plist
<key>LSApplicationQueriesSchemes</key>
<array>
<string>googlegmail</string>
<string>ms-outlook</string>
<string>readdle-spark</string>
<string>ymail</string>
</array>
I want to create an Android Style share feature for my app.
I created a share extension which gets called when you select pictures inside the stock photo app and press share.
Now I want those pictures to be sent to the main app and get handled over there.
My question is now:
Can iOS open my app after a button is pressed on the share extension window?
How do I get the picture files inside my main app?
Swift 4+ (tested on iOS 13)
#objc should be added to the declaration of openURL, that is,
#objc func openURL(_ url: URL) -> Bool {
// Code below.
}
Without it one would see this compiler error:
Argument of '#selector' refers to instance method 'openURL' that is not exposed to Objective-C
Working solution in Swift 3.1 (tested in iOS10):
You need to create your own URL Scheme, then add this function to your ViewController and call it with openURL("myScheme://myIdentifier")
// Function must be named exactly like this so a selector can be found by the compiler!
// Anyway - it's another selector in another instance that would be "performed" instead.
func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
Edit: Notes for clarification:
openURL is a method of UIApplication - since your ShareExtension is not derived from UIApplication I added my own openURL with the same definition as the one from UIApplication to keep the compiler happy (so that #selector(openURL(_:) can be found).
Then I go through the responders until I find one that is really derived from UIApplication and call openURL on that.
More stripped-down-example-code which copies files in a ShareExtension to a local directory, serializing filenames and calling openURL on another app:
//
// ShareViewController.swift
//
import UIKit
import Social
import MobileCoreServices
class ShareViewController: UIViewController {
var docPath = ""
override func viewDidLoad() {
super.viewDidLoad()
let containerURL = FileManager().containerURL(forSecurityApplicationGroupIdentifier: "group.com.my-domain")!
docPath = "\(containerURL.path)/share"
// Create directory if not exists
do {
try FileManager.default.createDirectory(atPath: docPath, withIntermediateDirectories: true, attributes: nil)
} catch let error as NSError {
print("Could not create the directory \(error)")
} catch {
fatalError()
}
// removing previous stored files
let files = try! FileManager.default.contentsOfDirectory(atPath: docPath)
for file in files {
try? FileManager.default.removeItem(at: URL(fileURLWithPath: "\(docPath)/\(file)"))
}
}
override func viewDidAppear(_ animated: Bool) {
let alertView = UIAlertController(title: "Export", message: " ", preferredStyle: .alert)
self.present(alertView, animated: true, completion: {
let group = DispatchGroup()
NSLog("inputItems: \(self.extensionContext!.inputItems.count)")
for item: Any in self.extensionContext!.inputItems {
let inputItem = item as! NSExtensionItem
for provider: Any in inputItem.attachments! {
let itemProvider = provider as! NSItemProvider
group.enter()
itemProvider.loadItem(forTypeIdentifier: kUTTypeData as String, options: nil) { data, error in
if error == nil {
// Note: "data" may be another type (e.g. Data or UIImage). Casting to URL may fail. Better use switch-statement for other types.
// "screenshot-tool" from iOS11 will give you an UIImage here
let url = data as! URL
let path = "\(self.docPath)/\(url.pathComponents.last ?? "")"
print(">>> sharepath: \(String(describing: url.path))")
try? FileManager.default.copyItem(at: url, to: URL(fileURLWithPath: path))
} else {
NSLog("\(error)")
}
group.leave()
}
}
}
group.notify(queue: DispatchQueue.main) {
NSLog("done")
let files = try! FileManager.default.contentsOfDirectory(atPath: self.docPath)
NSLog("directory: \(files)")
// Serialize filenames, call openURL:
do {
let jsonData : Data = try JSONSerialization.data(
withJSONObject: [
"action" : "incoming-files"
],
options: JSONSerialization.WritingOptions.init(rawValue: 0))
let jsonString = (NSString(data: jsonData, encoding: String.Encoding.utf8.rawValue)! as String).addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
let result = self.openURL(URL(string: "myapp://com.myapp.share?\(jsonString!)")!)
} catch {
alertView.message = "Error: \(error.localizedDescription)"
}
self.dismiss(animated: false) {
self.extensionContext!.completeRequest(returningItems: [], completionHandler: nil)
}
}
})
}
// Function must be named exactly like this so a selector can be found by the compiler!
// Anyway - it's another selector in another instance that would be "performed" instead.
#objc func openURL(_ url: URL) -> Bool {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application.perform(#selector(openURL(_:)), with: url) != nil
}
responder = responder?.next
}
return false
}
}
Technically you can't open containing app from share extension, but you can schedule local notification, and that's what I end up doing. Just before I call super.didSelectPost, I schedule local notification with some text, and if user wants to open containing app, they can, and if not - they can continue with their workflow. I even think its a better approach than automatically opening containing app and disrupting what they are doing.
Currently there's no way to do this. A share extension cannot open the containing app.
The intended approach for share extensions is that they handle all of the necessary work themselves. Extensions can share code with their containing apps by using custom frameworks, so in most cases that's no problem.
If you want to make data available to your app, you can set up an app group so that you have a shared directory. The extension can write data there, and the app can read it. That won't happen until the next time the user launches the app, though.
I opened the host app from shared extension with a trick.
Using a webview with clear background color.
below is the code
NSString *customURL = #"MY_HOST_URL_SCHEME_APP://";
UIWebView *webView = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 300, 400)];
webView.backgroundColor = [UIColor clearColor];
webView.tintColor = [UIColor clearColor];
[webView setOpaque:NO];
[self.view addSubview:webView];
NSURLRequest *urlRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:customURL]];
[webView loadRequest:urlRequest];
[self didSelectCancel];
Implement custom url schema in host app and call openURL(url:) method
like openURL(url:NSURL(string:"schema_name://"))
extension SLComposeServiceViewController {
func openURL(url: NSURL) -> Bool {
do {
let application = try self.sharedApplication()
return application.performSelector("openURL:", withObject: url) != nil
}
catch {
return false
}
}
func sharedApplication() throws -> UIApplication {
var responder: UIResponder? = self
while responder != nil {
if let application = responder as? UIApplication {
return application
}
responder = responder?.nextResponder()
}
throw NSError(domain: "UIInputViewController+sharedApplication.swift", code: 1, userInfo: nil)
}
}
Xamarin.iOS version of #coyer answer:
using System;
using Foundation;
using UIKit;
using MobileCoreServices;
using CoreFoundation;
using System.Linq;
using Newtonsoft.Json;
using System.Collections.Generic;
using ObjCRuntime;
using System.Runtime.InteropServices;
namespace Your.ShareExtension
{
public partial class ShareViewController : UIViewController
{
public ShareViewController(IntPtr handle) : base(handle)
{
}
string docPath = "";
public override void ViewDidLoad()
{
base.ViewDidLoad();
try
{
var containerURL = new NSFileManager().GetContainerUrl("group.com.qsiga.startbss");
docPath = $"{containerURL.Path}/share";
// Create directory if not exists
try
{
NSFileManager.DefaultManager.CreateDirectory(docPath, true, null);
}
catch (Exception e)
{ }
// removing previous stored files
NSError contentError;
var files = NSFileManager.DefaultManager.GetDirectoryContent(docPath, out contentError);
foreach (var file in files)
{
try
{
NSError err;
NSFileManager.DefaultManager.Remove($"{docPath}/{file}", out err);
}
catch (Exception e)
{ }
}
}
catch (Exception e)
{
Console.WriteLine("ShareViewController exception: " + e);
}
}
public override void ViewDidAppear(bool animated)
{
var alertView = UIAlertController.Create("Export", " ", UIAlertControllerStyle.Alert);
PresentViewController(alertView, true, () =>
{
var group = new DispatchGroup();
foreach (var item in ExtensionContext.InputItems)
{
var inputItem = item as NSExtensionItem;
foreach (var provider in inputItem.Attachments)
{
var itemProvider = provider as NSItemProvider;
group.Enter();
itemProvider.LoadItem(UTType.Data.ToString(), null, (data, error) =>
{
if (error == null)
{
// Note: "data" may be another type (e.g. Data or UIImage). Casting to URL may fail. Better use switch-statement for other types.
// "screenshot-tool" from iOS11 will give you an UIImage here
var url = data as NSUrl;
var path = $"{docPath}/{(url.PathComponents.LastOrDefault() ?? "")}";
NSError err;
NSFileManager.DefaultManager.Copy(url, NSUrl.CreateFileUrl(path, null), out err);
}
group.Leave();
});
}
}
group.Notify(DispatchQueue.MainQueue, () =>
{
try
{
var jsonData = JsonConvert.SerializeObject(new Dictionary<string, string>() { { "action", "incoming-files" } });
var jsonString = NSString.FromData(jsonData, NSStringEncoding.UTF8).CreateStringByAddingPercentEncoding(NSUrlUtilities_NSCharacterSet.UrlQueryAllowedCharacterSet);
var result = openURL(new NSUrl($"startbss://share?{jsonString}"));
}
catch (Exception e)
{
alertView.Message = $"Error: {e.Message}";
}
DismissViewController(false, () =>
{
ExtensionContext?.CompleteRequest(new NSExtensionItem[] { }, null);
});
});
});
}
public bool openURL(NSUrl url)
{
UIResponder responder = this;
while (responder != null)
{
var application = responder as UIApplication;
if (application != null)
return CallSelector(application, url);
responder = responder?.NextResponder;
}
return false;
}
[DllImport(Constants.ObjectiveCLibrary, EntryPoint = "objc_msgSend")]
static extern bool _callSelector(
IntPtr target,
IntPtr selector,
IntPtr url,
IntPtr options,
IntPtr completionHandler
);
private bool CallSelector(UIApplication application, NSUrl url)
{
Selector selector = new Selector("openURL:options:completionHandler:");
return _callSelector(
application.Handle,
selector.Handle,
url.Handle,
IntPtr.Zero,
IntPtr.Zero
);
}
}
}
I'm able to get this working by accessing the shared UIApplication instance via key-value coding and calling openURL on that:
let application = UIApplication.value(forKeyPath: #keyPath(UIApplication.shared)) as! UIApplication
let selector = NSSelectorFromString("openURL:")
let url = URL(string: "jptest://")!
application.perform(selector, with: url)
I was having this problem, and in iOS 11+ none of the previous answers work. I ended up adding a completion handler to my JavaScript code, and from there setting window.location="myapp://". It's a bit hacky but it doesn't look to bad and the user can follow along.
Not only there is no way (and won't be) to do this:
there is no NEED to handle this in the app.
The extension is supposed to handle this with the very
same codebase as the main app. You should create a framework
with extension safe API shared between the app and the extesnion targets.
This is the top topic here:
https://developer.apple.com/library/content/documentation/General/Conceptual/ExtensibilityPG/ExtensionScenarios.html#//apple_ref/doc/uid/TP40014214-CH21-SW1
Extra rationale: in the extension you'd have to work with a much
smaller memory allowance meaning: if you use the images
of decent size as in the main app you will likely crash and burn.
In extension you'd have to work with jpeg or reasonable small size
and even then make sure size is small enough otherwise you'd be booted out trying to unpack the image from disk into memory
(see size limitation above)
EDIT: This solution works for today extension (Widget).
An extension can open the hosting app:
- (IBAction)launchHostingApp:(id)sender
{
NSURL *pjURL = [NSURL URLWithString:#"hostingapp://home"];
[self.extensionContext openURL:pjURL completionHandler:nil];
}
And like Apple says in Handling Commons Scenarios :
An extension doesn’t directly tell its containing app to open; instead, it uses the openURL:completionHandler: method of NSExtensionContext to tell the system to open its containing app. When an extension uses this method to open a URL, the system validates the request before fulfilling it.