Opening iMessage with default body containing a link - swift

I am trying to open up the iMessage app with a default message from my app. The default message contains a link to the app in the app store. This is used as a way for users to invite people to download the app.
The user types in a number and then hits a submit button and then it opens up the iMessage app with that number and a refilled message. However, for some reason, Swift won't generate the URL. Here is what I have
let body = "Download SomeApp by clicking the link below:\n\nhttps://appsto.re/us/someapp.i"
guard let phoneUrl = URL(string: "sms:\(numberTextField.text!)&body=\(body)") else {
return
}
if UIApplication.shared.canOpenURL(phoneUrl) {
UIApplication.shared.open(phoneUrl, options: [:], completionHandler: nil)
}
Right now its not even getting past the guard statement.
All I want to do is open iMessage with a link to my app in the body.

You need to escape the content passed into the &body= parameter. You can do this with addingPercentEncoding.
For example:
let body = "Download SomeApp by clicking the link below:\n\nhttps://appsto.re/us/someapp.i"
guard let escapedBody = body.addingPercentEncoding(withAllowedCharacters: .urlHostAllowed) else {
return
}
guard let phoneUrl = URL(string: "sms:\(numberTextField.text!)&body=\(escapedBody)") else {
return
}

Related

Macos WKWebView only gets partial content

I am trying to use a Macos WKWebView to get the text content of a Facebook page. However, the WKWebView's load method only gets a small part of the Facebook page: I need to scroll down manually several dozen times in order to get more and more content. How can I automatize the process to load the full page?
func getPageContent(url: URL) {
let urlRequest = URLRequest (url:url)
myWebView.load(urlRequest)
myWebView.evaluateJavaScript("document.body.innerHTML;") { (result,error) in
if error != nil {
print(error!.localizedDescription)
} else {
// grab text
rawHtml = result as! String
// rawHtml contains only a small part of the page!
}
}

When I redirect the user from ShareExtensions to the App, the App opens but then instantly closes

As written in the subject, I would like to redirect the user to my App when he's using share extensions. For example when he tries to share a photo through my app - he opens the images, clicks on share, selects my app and then he is redirected to the app. He is in fact, but when he is, the app opens and then instantly closes. I made the solution in reference to this:
https://kitefaster.com/2016/07/13/how-to-open-ios-app-with-custom-url/
(adding all the necessary stuff in plist)
And in Share Extensions I made the following function:
func redirectToApp() {
let urlString = "myAppName://"
let url = NSURL(string: urlString)
let selectorOpenURL = sel_registerName("openURL:")
let context = NSExtensionContext()
context.open(url! as URL, completionHandler: nil)
var responder = self as UIResponder?
while (responder != nil) {
if responder?.responds(to: selectorOpenURL) == true {
responder?.perform(selectorOpenURL, with: url)
}
responder = responder!.next
}
}

Implementing "Open file with" in Swift Cocoa App

I'm working on a macOS cocoa-app in Swift where I import several different file types into the app for the user to interact with.
I'm currently trying to determine if it's possible to implement the "Open file with" feature, so that the user could open those files in a different program if they wanted to:
I've found a few different SO questions that seem tangentially related to what I'm trying to do:
Swift: How to open file with associated application?
Launch OSX Finder window with specific files selected
...but so far nothing to indicate if it's possible to implement right-click Finder/file (?) access in the way I had in mind.
Apologies if this is too vague of a question; any help / guidance appreciated!
Without going into details, it's pretty straight forward:
Get the list of all known applications that can open a specific file type (see LSCopyApplicationURLsForURL, a Core Foundation C function).
Build the menu. You can use NSWorkspace (and probably URL) to get the application icons.
Use NSWorkspace.openFile(_:withApplication:) to tell the application to open the given document.
2022, Swift 5
Get app list associated with local file:
func getAppsAssociatedWith(_ url: URL?) {
guard let url = localFileURL,
let retainedArr = LSCopyApplicationURLsForURL( url as CFURL, .all)?.takeRetainedValue(),
let listOfRelatedApps = retainedArr as? Array<URL>
else {
return []
}
return listOfRelatedApps
}
Getting thumbnail for app:
let singleAppIcon = NSWorkspace.shared
.icon(forFile: appUrl.path)
.scaledCopy(sizeOfLargerSide: 17)
Open url with app:
#available(macOS 10.15, iOS 9.0, *)
public class func openUrlWithApp(_ urls: [URL], appUrl: URL) {
NSWorkspace.shared.open(urls, withApplicationAt: appUrl, configuration: NSWorkspace.OpenConfiguration())
}
In my app I'm cashing all apps icons in dictionary.
[someFile localURL : app icon]
If I have already got icon earlier - no need to get it once more
var relatedAppsThumbnails: [URL: Image] = [:]
func updateRelatedApps() {
guard let url = currImgUrl, // file url to get icons from related apps
let retainedArr = LSCopyApplicationURLsForURL( url as CFURL, .all)?.takeRetainedValue(),
let listOfRelatedApps = retainedArr as? Array<URL>
else {
relatedApps = []
return
}
self.relatedApps = listOfRelatedApps
// add app icon in case of it wasn't added yet
for appUrl in listOfRelatedApps {
if relatedAppsThumbnails[appUrl] == nil {
let nsImg = NSWorkspace.shared.icon(forFile: appUrl.path)
.scaledCopy(sizeOfLargerSide: 17)
relatedAppsThumbnails[appUrl] = Image(nsImage: nsImg)
}
}
}
LSCopyApplicationURLsForURL is deprecated. You can use this alternative:
func getListOfExternalApps(forURL url: URL) -> [(URL, Image)] {
let listOfExternalApps = NSWorkspace.shared.urlsForApplications(toOpen: url)
let icons = listOfExternalApps.map {
let nsimage = NSWorkspace.shared.icon(forFile: $0.path())
nsimage.size = CGSize(width: .s16, height: .s16)
return Image(nsImage: nsimage)
}
return Array(zip(listOfExternalApps, icons))
}

WKWebKit does not refresh webpage

I am using Xcode 8.3.3 and Swift 3 to develop an app for the iMac using Cocoa. My goal is to use VCgoToWebPage and display a webpage to the user. My program calls this function many times, but the only webpage I see is the last one called. How do I implement a window refresh inside this function and wait for the webpage to be fully rendered?
func VCgoToWebPage(theWebPage : String) {
let url = URL(string: theWebPage)!
let request = URLRequest(url: url)
webView.load(request)
/*The modal box allows the web pages to be seen. Without it, after a series of calls to VCgoToWebPage only the last page called is displayed. The modal box code is just for debugging and will be removed. */
let alert = NSAlert()
alert.messageText="calling EDGAR page"
alert.informativeText=theWebPage
alert.addButton(withTitle: "OK")
alert.runModal()
}
You can use navigation delegate to make sure navigation to a page is complete before trying to load another. Have your class conform to WKNavigationDelegate and set webView.navigationDelegate to that class instance.
var allRequests = [URLRequest]()
func VCgoToWebPage(theWebPage : String) {
guard let url = URL(string: theWebPage) else {
return
}
let request = URLRequest(url: url)
if webView.isLoading{
allRequests.append(request)
} else {
webView.load(request)
}
}
func webView(WKWebView, didFinish: WKNavigation!){
if let nextRequest = allRequests.first{
webView.load(nextRequest)
allRequests.removeFirst()
}
}

How to make phone calls in swift

First of all I know there are some similar topics as this one but because of my reputation I couldn't comment on those for help and stack overflow warned me not to ask for help from the answers section.. none of the similar posts have answered my question so here I go.
As can be understood from the topic, I want make a phone call on click,
I'm making an app for my business and I want to put in a call button so that people can call me over the app.
here are the attempts I've tried as read from the similar topics:
let phoneNumber = "1234567890"
if let phoneCallURL = NSURL(string: "tel:\(phoneNumber)") {
let application = UIApplication.sharedApplication()
if application.canOpenURL(phoneCallURL) {
application.openURL(phoneCallURL)
}
else{
println("failed")
}
}
so when I run the above code with a phone number it prints out the failed message on the console seems like i fails opening the URL
The other code I've tried is a very similar one
var url:NSURL = NSURL(string: "tel://phoneNumber")!
UIApplication.sharedApplication().openURL(url)
one other question is that: What is the correct syntax for the NSURL?
this
NSURL(string: "tel://\(phoneNumber)")
or this
NSURL(string: "tel//:\(phoneNumber)")
My last question is: If the app manages to make a call, does it appear on the simulator like a calling screen? I'm very new to swift programming and I apologise if the questions seem stupid..
The simple format for a tel: URL is tel:######. / is not a number. You probably mean this to be:
NSURL(string: "tel:\(phoneNumber)")
assuming phoneNumber is a string containing the phone number.
The tel: scheme is defined in RFC2806. You can look there for details on all its expected features.
Note that phone calls are not possible in the simulator, so you'll receive an error if you try to open a tel: URL there (unless you handle the URL yourself by registering an NSURLProtocol).
If you want to return to your app after your call has been ended (which you should do) then you need to use telprompt:// instead of tel://. The tel:// will take you to the home screen after the call.
Better use this:
var url:NSURL = NSURL(string: "telprompt://1234567891")!
UIApplication.sharedApplication().openURL(url)
let phoneNumber = "0507712323"
if let callNumber = phoneNumber {
let aURL = NSURL(string: "telprompt://\(callNumber)")
if UIApplication.sharedApplication().canOpenURL(aURL) {
UIApplication.sharedApplication().openURL(aURL)
} else {
print("error")
}
}
else {
print("error")}
I have this issue for different reasons and I would like share with you .
First Dont try in simulator must try on real device
Second make sure the passed number dont contain space
here is example
private func callNumber(phoneNumber:String) {
// I add this line to make sure passed number wihthout space
let CleanphoneNumber = phoneNumber.stringByReplacingOccurrencesOfString(" ", withString: "")
if let phoneCallURL:NSURL = NSURL(string: "tel://\(CleanphoneNumber)") {
let application:UIApplication = UIApplication.sharedApplication()
if (application.canOpenURL(phoneCallURL)) {
application.openURL(phoneCallURL);
}
}
}
Your code looks correct.It seems that it would always fail if you test it in simulator.
Try to use your iPhone to run it,and it would go to dialer interface as you want.
i added some additional validation in the code
func makeCall(constactNumber : NSString)
{
if(constactNumber.length == 0)
{
print("Contact number in not valid")
}
else
{
let CleanconstactNumber = constactNumber.stringByReplacingOccurrencesOfString(" ", withString: "")
if let phoneCallURL:NSURL = NSURL(string: "tel://\(CleanconstactNumber)")
{
if (UIDevice.currentDevice().model.rangeOfString("iPad") != nil)
{
print("Your device doesn't support this feature.")
} else
{
let application:UIApplication = UIApplication.sharedApplication()
if (application.canOpenURL(phoneCallURL))
{
let mobileNetworkCode = CTTelephonyNetworkInfo().subscriberCellularProvider?.mobileNetworkCode
if( mobileNetworkCode == nil)
{
print(" No sim present Or No cellular coverage or phone is on airplane mode.")
}
else
{
application.openURL(phoneCallURL);
}
}
}
}
}
}