What i'm trying to do is open a website in Safari, through having the user click on a link that is displayed in my UIWebView.
I started by reading through the question/answers on:
Open specific link in Safari from UIWebView
Afterwhich I implemented the following:
class HomeInfoView: UIViewController, UIWebViewDelegate{
override func viewDidLoad() {
super.viewDidLoad()
let localfilePath = NSBundle.mainBundle().URLForResource("homeInfo", withExtension: "html");
let myRequest = NSURLRequest(URL: localfilePath!);
WebViewer.loadRequest(myRequest);
WebViewer.scrollView.bounces = false
}
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
if let url = request.URL where navigationType == UIWebViewNavigationType.LinkClicked {
UIApplication.sharedApplication().openURL(url)
return false
}
return true
}
However when trying to use the link I still get an error
"App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file."
I think I'm 90% of the way there, yet I'm not sure how to edit my .plist to allow the exception. Or if there is something else that I've missed.
(I would've added this as a comment to the original post but my rank isn't high enough yet)
You will need to either grant permission to that specific domain in your info.plist :
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>testdomain.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionAllowsInsecureHTTPLoads</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSThirdPartyExceptionAllowsInsecureHTTPLoads</key>
<false/>
<key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
<true/>
<key>NSThirdPartyExceptionMinimumTLSVersion</key>
<string>TLSv1.2</string>
<key>NSRequiresCertificateTransparency</key>
<false/>
</dict>
</dict>
</dict>
This info in your plist basically sets up an exception in your app. It allows you to access the testdomain.com domain (insert whatever domain you are trying to access). It lets you access all of the subdomains and then sets a minimum TLS version to help ensure the site you are connecting to is the one you want.
Or you you can simply allow access to all http websites, which is not recommended.
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
This isn't recommended because it allows your app to access any http:// domain, which can be a security problem because it can make your app vulnerable to man-in-the-middle attacks.
Check out Apple's documentation for more info on this.
https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW33
Related
i am encountering a weird issue.
Short version
We have an app in the appstore for multiple months now with a photo feed. We have plenty of users (99,9% in Europe, mostly Central Europe).
using SDwebImage for image downloading
Backblaze as cloud storage
The issue:
On our end there is no issue. And none of our users encounter issues when showing the images.
However when Apple reviews our app, they are not able to download images at all (the exact same which work for us and all users).
What we tested
SDWebImage was shortly replaced with Kingfisher -> same result
We tried to reproduce the issue but weren't able: We set the location of our simulator to all possible locations + changed languages, clean rebuild etc. Never encountered the issue.
We tried around with AllowArbitrary loads but still won't work for our Apple reviewer.
Code
postImageView.sd_imageIndicator?.startAnimatingIndicator()
let photoUrl = URL(string: photoUrlString)
postImageView.backgroundColor = .systemGray3
postImageView.sd_imageIndicator = SDWebImageActivityIndicator.grayLarge
SDWebImageDownloader.shared.config.downloadTimeout = 40
postImageView.sd_setImage(with: photoUrl, placeholderImage: nil, options: .allowInvalidSSLCertificates) { (image, err, sd, url) in
self.postImageView.sd_imageIndicator = nil
self.postImageView.sd_imageIndicator?.stopAnimatingIndicator()
if err != nil {
self.postImageView.image = UIImage(named: "placeholder-image")
Ref().databaseProblems.child("IMAGE_IOS").child(UUID().uuidString).setValue("\(err.debugDescription) + \(err?.localizedDescription ?? "")")
}
}
the error codes
Optional(Error Domain=NSURLErrorDomain Code=-1001 \"The request timed out.\" UserInfo={_kCFStreamErrorCodeKey=60, NSUnderlyingError=0x28334f120 {Error Domain=kCFErrorDomainCFNetwork Code=-1001 \"(null)\" UserInfo={_kCFStreamErrorCodeKey=60, _kCFStreamErrorDomainKey=1}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <49574986-C917-4980-ABC7-6A9E9EBD6892>.<3>, _NSURLErrorRelatedURLSessionTaskErrorKey=(\n \"LocalDataTask <49574986-C917-4980-ABC7-6A9E9EBD6892>.<3>\"\n), NSLocalizedDescription=The request timed out., NSErrorFailingURLStringKey=https://f000.backblazeb2.com/file/Images/-MVVvWz3rlPQw5J5_Ah_, NSErrorFailingURLKey=https://f000.backblazeb2.com/file/Images/-MVVvWz3rlPQw5J5_Ah_, _kCFStreamErrorDomainKey=1}) + The request timed out."
"Optional(Error Domain=SDWebImageErrorDomain Code=2002 \"Operation cancelled by user during sending the request\" UserInfo={NSLocalizedDescription=Operation cancelled by user during sending the request}) + Operation cancelled by user during sending the request"
"Optional(Error Domain=NSURLErrorDomain Code=-1022 \"The resource could not be loaded because the App Transport Security policy requires the use of a secure connection.\" UserInfo={NSLocalizedDescription=The resource could not be loaded because the App Transport Security policy requires the use of a secure connection., NSErrorFailingURLStringKey=http://f000.backblazeb2.com/file/Images/-MVTKiJrFDOldW94d0cO, NSErrorFailingURLKey=http://f000.backblazeb2.com/file/Images/-MVTKiJrFDOldW94d0cO, _NSURLErrorRelatedURLSessionTaskErrorKey=(\n \"LocalDataTask <F3ADD147-226D-48EF-8B3A-2C61EF2887FE>.<2>\"\n), _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <F3ADD147-226D-48EF-8B3A-2C61EF2887FE>.<2>, NSUnderlyingError=0x60400036d550 {Error Domain=kCFErrorDomainCFNetwork Code=-1022 \"(null)\"}}) + The resource could not be loaded because the App Transport Security policy requires the use of a secure connection."
info.plist
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>https://f000.backblazeb2.com</key>
<dict>
<key>NSIncludesSubdomains</key>
<true/>
<key>NSExceptionRequiresForwardSecrecy</key>
<false/>
</dict>
</dict>
</dict>
Any idea/suggestion?
(I've never used Swift or Xcode before so this is probably a stupid question)
To isolate the issue, I created a totally empty "App" in Xcode 11, and put this into the AppDelegate.swift:
import Cocoa
import EventKit
#NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
private let eventStore = EKEventStore()
func applicationDidFinishLaunching(_ aNotification: Notification) {
eventStore.requestAccess(to: .event) { granted, error in
if granted {
print("GOOD: Access granted")
} else {
print("BAD: Access denied")
}
}
}
}
When I run the app (via cmd+R), I immediately see that it denied access, without ever giving me the chance to approve access:
Metal API Validation Enabled
BAD: Access denied
What am I doing wrong? How can I get it to allow me to approve access to calendar events?
Note that I noticed that the docs say:
To access the user’s Calendar data, all sandboxed macOS apps must include the com.apple.security.personal-information key.
So I made that change like so in App_Name.entitlements but it didn't help:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.personal-information</key>
<true/>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>
<true/>
</dict>
</plist>
Fixed. 2 things I had wrong:
com.apple.security.personal-information in the entitlements file was incorrect. Just typing "Calendar" autocompletes to the correct one.
In the Info.plist file, I needed "Privacy - Calendars Usage Description" to have a value. I found that here: https://forums.developer.apple.com/thread/110825
I'm working on a project where I want to load a internet URL to my UIWebView
I've managed to load a locally stored html file like this:
if let url = NSBundle.mainBundle().URLForResource("index", withExtension: "html") {
webView.loadRequest(NSURLRequest(URL: url))
}
So based on that I tried doing it like this:
if let url = NSURL(string: "http://google.com") {
webView.loadRequest(NSURLRequest(URL: url))
}
But that didn't seem to work.
Apple introduced App Transport Security with iOS9. That is a new security feature that enforces certain security practices when working with web requests. For example it won't allow to send requests via HTTP, because it only allows HTTPS requests. The good news is that you can override these security requirements by adding this to your project's Info.plist file:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
Just be aware that this circumvents ALL security requirements that came with ATS.
You should use this in production only if there really is no other way. If you only access 1 non HTTP url you can disable ATS for that 1 domain only:
<key>NSAppTransportSecurity</key>
<dict>
<key>NSExceptionDomains</key>
<dict>
<key>yourdomain.com</key>
<dict>
<!--Include to allow subdomains-->
<key>NSIncludesSubdomains</key>
<true/>
<!--Include to allow HTTP requests-->
<key>NSTemporaryExceptionAllowsInsecureHTTPLoads</key>
<true/>
</dict>
</dict>
</dict>
As joern says,the security update requires all requests to be via HTTPS if you don't want to override it.
So the basic quick fix to this would be just changing the link to https.
So something like this:
if let url = NSURL(string: "https://google.com") {
webView.loadRequest(NSURLRequest(URL: url))
}
Try below code :
let url = "http://google.com"
let requestURL = NSURL(string:url)
let request = NSURLRequest(URL: requestURL!)
WebView.loadRequest(request)
I'have used the following code to redirect the user to a facebook page.
NSURL *webURL = [NSURL URLWithString:#"https://m.facebook.com/icc"];
[[UIApplication sharedApplication] canOpenURL:webURL];
After updating to ios9, the above code is not working.
I have added following block in plist file. But not working.
<key>LSApplicationQueriesSchemes</key>
<array>
<string>fbapi</string>
<string>fb</string>
<string>fbauth2</string>
<string>fbshareextension</string>
<string>fb-messenger-api</string>
<string>twitter</string>
<string>whatsapp</string>
<string>wechat</string>
<string>line</string>
<string>instagram</string>
<string>kakaotalk</string>
<string>mqq</string>
<string>vk</string>
<string>mqq</string>
</array>
Is anything i missed here?
There are two URL related methods that are available. canOpenURL and openURL.
canOpenURL returns a yes or no answer after checking if there is any apps installed on the device that know how to handle a given URL.
openURL is used to actually launch the URL, which will typically leave the app and open the URL in another app.
And in your case i have tried the same code its working fine for me i means in case of canOpenURL its returning YES and when i call openURL its opening the safari and yes its same what you did.
For all developers having the same issue, the solution is to add a whitelist of all URL schemes your App may need to call into the Info.plist. The key to add is LSApplicationQueriesSchemes and its value is an array with all the URL schemes.
I have setup a view in my appcelerator titanium app to be nearly identical to the one in the kitchen sink demo for facebook login. I want to use single sign on for IOS:
//LoginView Component Constructor
function LoginView() {
//create object instance, a parasitic subclass of Observable
var self = Ti.UI.createView();
// APP ID BELOW IS CHANGED FOR DEMO PURPOSES
Titanium.Facebook.appid = "111111111111111";
Titanium.Facebook.permissions = ['email', 'publish_actions'];
// ENABLE SINGLE SIGN ON
Titanium.Facebook.forceDialogAuth = false;
self.add(Titanium.Facebook.createLoginButton({
style:Ti.Facebook.BUTTON_STYLE_WIDE,
bottom:30
}));
return self;
}
module.exports = LoginView;
When clicking the login button, it successfully opens the facebook login dialog in safari and I login. Then when it tries to take me back to the app, I get the error:
Cannot Open the Page Safari cannot open the page because the address
is invalid
Very similar code works correctly in the kitchen sink app, and also disabling single sign on makes logging in through facebook work correctly in my app.
All I have for the settings in the facebook app is:
Facebook Login - Enabled
Am I missing anything from the settings?
Figured it out:
In my facebook app settings (on developers.facebook.com), I set the bundle Id to the same id as my app in Appcelerator.
Based on the q & a:
Copied Info.plist from build/iphone/ into the root of the application.
Added the xml element fb111111111111111 below under app to Info.plist:
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.mycompany.app</string>
<key>CFBundleURLSchemes</key>
<array>
<string>app</string>
<string>fb111111111111111</string>
</array>
</dict>
</array>
Where 111111111111111 is changed to the id of the app