In the StageWebView in Air for iOS, if there is a SSL certificate error, by default it will prompt the user with:
"A secure connection with this site cannot be verified. Would you
still like to proceed?
The certificate you are viewing does not match the name of the site
you are trying to view."
When this occurs, is there any way to stop the message from occurring and just hide the webview?
I've added error handling code:
function webview_error(event:ErrorEvent) {
trace(event);
webView.stage = null;
isConnected = false;
}
But it only fires if the user hits "No" I don't want them to have that option to avoid Man in the Middle attacks.
Thanks.
Related
I'm using the iOS LinkedIn SDK to log into my App and retrieve basic profiles.
All works perfectly fine the first time I login, until either I log out, or I close my App.
On attempting to log back into my App with LinkedIn: the usual redirect to the LinkedIn app takes place, but the permissions screen for my app doesn't pop up, it just redirects straight back to my app with the following error:
Error Domain=LISDKAuthError Code=5 "(null)" UserInfo={errorDescription=The operation couldn’t be completed. Software caused connection abort, originalDomain=LISDKServerError, errorInfo=PARSING_ERROR}
I can only successfully log back in again if I first close the LinkedIn App, before reopening mine.
Does anyone have an idea of what's going on please?
-This doesn't occur on all of my test devices!
-On the device that it does occur on, I also receive the same error in that scenario when running the sample App provided with the LinkedIn SDK.
-The LinkedIn App is up to date.
-The App id, bundle ids etc etc are all set, hence login success half of the time!
-I've tried calling [LISDKSessionManager clearSession] in numerous locations.
Cheeky framework fix alert.
Uncomment out the lines in LISDKSession.h
This allows the correct use of [LISDKSessionManager hasValidSession]
Which is an improvement on what we were working with.
Not yet tested with iOS12...
I had a similar problem. It was mainly reproduced only on iOS 12. The problem is that when you already have a LinkedIn application running, you will not be able to log in through their SDK in your application. On iOS 11, the second time you try to log in after this error, the authorization worked fine.
I solved this issue by simply showing the user an alert with a message about what he needs to do to authorize.
Here you can check an example of my implementation in Swift 4:
LISDKSessionManager.createSession(withAuth: ["r_basicprofile"],
state: nil,
showGoToAppStoreDialog: true,
successBlock: { _ in
// Your actions in case of successful authorization
}, errorBlock: { error in
guard let nsError = error as NSError? else {
return
}
if #available(iOS 12.0, *),
nsError.code == LISDKErrorCode.SERVER_ERROR.rawValue {
// Show alert to user with text - "Please, shut down the LinkedIn app and try login again"
} else if nsError.code != LISDKErrorCode.USER_CANCELLED.rawValue {
// Handling when user tap on Cancel button in LinkedIn SDK
}
})
I've been battling for a fix for this with LinkedIn for months.
There 'solution' is to kill off the SDK.
Taken from their 'Important updates to the LinkedIn Developers program and APIs' email December 2018:
"Authentication, SDKs, and Plugins: We are also deprecating several obsolete or seldomly-used products and technologies."
"SDKs: Our JavaScript and Mobile Software Development Kits (SDKs) will stop working. Developers will need to migrate to using OAuth 2.0 directly from their apps."
Uncomment this two lines of code in LISDKSession.h
- (LISDKAccessToken *)getAccessToken;
- (void)setAccessToken:(LISDKAccessToken *)accessToken;
I know it has been asked before but I am asking again to make sure I didn't miss anything. I am currently using the next code in order to connect a specific hotspot. This prompt a message to the user -
let configuration = NEHotspotConfiguration(ssid: ssid,
passphrase: password,
isWEP: false)
NEHotspotConfigurationManager.shared.apply(configuration)
Is there anyway I can connect automatically without prompting this message? I need to switch between hotspots every few minutes. I don't mind showing the message once and after that connecting automatically but is there any way I can do it?
EDIT: DEAR PEOPLE FROM THE FUTURE, trey-jones has fixed this issue by implementing setLoginBehavior, FBSDKLoginNative seems to have issues on FB's end not with the module.
Environment:
MacOS X 10.10.5
Ti SDK 5.1.1.GA - 5.1.2.GA
iOS 9.2
Ti.Facebook 5.0.0 - 5.0.1
My project settings (tiapp.xml) are fine (it works on every other case on both iOS and Android).
Code I'm using to invoke the login:
var fb = require('facebook');
fb.initialize();
fb.authorize();
If the Facebook app is installed to the device the fb.authorize() doesn't open up. I did not see any iOS system level messages when this happened either.
Has anyone else had luck using fb.authorize with the new sdk on iOS devices WITH the app installed. With no fb app on the system it correctly opens the browser based view.
EDIT: I have managed a workaround for this (it is not pretty) based on the fact that login works with AppC's KitchenSink.
The workaround is to add a Ti.FB loginButton to the code, doesn't matter if its not visible, initializing this will fix whatever is causing custom login's .authorize() to not work.
//Workaround button:
if(OS_IOS){
var fbHaxBtn = fb.createLoginButton({
readPermissions: ['email'],
visible: false
});
}
//It needs to be added to the window/doesn't need to be visible though
$.login_window.add(fbHaxBtn);
//Then in our custom button's code, we can fire as normal:
function doLoginClick{
fb.initialize(); //I was having unexpected issues dropping this line on Android, although the docs say its deprecated.
fb.authorize();
}
Will keep this ticket updated if/when this thing gets a formal fix.
This is my second answer on this question. I believe that my original answer offers some value to the conversation and that is why I am leaving it, but it still did not consistently solve the problem of the facebook authorization not working.
The consistent solution turned out to be modifying the official Ti.Facebook module. I will submit a pull request for this change (1 line), but for now, you can get the working module here:
Source
Pre-built
This consistently allows users to authorize by explicitly setting the login behavior to use the browser, rather than the native facebook app through fast app-switching. This is actually the intent of Facebook's developers.
I was unable to determine what is causing it to fizzle when trying to use the native app to login - it should try the next option, which is the browser - but this works, and doesn't require a TiFacebookButton either.
I hope it helps someone else!
EDIT: This answer does not solve the original question. I have left it here in case it helps with related difficulties using the Ti.Facebook module. See my other answer, to actually solve the problem. END EDIT
I commented above, but after doing so encountered some more strange behavior, with the result being that I could not reliably use the workaround given (fbHaxButton). I want to explain what was happening in my case, and show my own workaround (which is also not pretty). It's possible that the root cause is the same for both of us.
I have not bothered with Android yet, so this answer is specific to iOS.
When I started this process, I came to the conclusion that authorize was correctly opening the facebook website in safari to allow authorization, but was not firing the login event upon returning. To handle this I had already implemented the following:
facebook = require('facebook');
Ti.App.addEventListener('resumed', function (e) {
var launchOptions = Ti.App.getArguments();
if(!launchOptions.url) {
return console.warn('Ignoring resume event with no url argument.');
}
// this lib = https://github.com/garycourt/uri-js
var URI = require('vendor/uri'),
uriComponents = URI.parse(launchOptions.url),
expectedScheme = 'fb',
expectedHost = 'authorize';
// I would like to be more specific about the uri, but we are limited
// in Titanium, and this will allow us to pretty certain
// that FB is sending us back to our app
if(uriComponents.scheme.search(expectedScheme) < 0 || uriComponents.host !== expectedHost) {
return console.warn('Resume event received, but scheme is incorrect. Ignoring.');
}
// synthesize login event
facebook.fireEvent('myapp:login', {
success: 1,
token: facebook.getAccessToken(),
uid: result.id
});
});
facebook.addEventListener('myapp:login', function onFacebookAuth(e) {
facebook.removeEventListener('myapp:login', onFacebookAuth);
if(!e.success) {
// do fail action
}
// do success action
});
facebook.initialize();
facebook.authorize();
So, originally I was firing and listening for an event called 'login', which the facebook module supposedly (according to the docs) will fire after authorization is complete.
In my case, this event was being fired while my app was in the background, after authorize was called, but before the user actually clicked 'OK' in facebook. My listener would respond to this event (logging, etc), but seemed to occur in a separate thread, or somehow otherwise become disconnected from my app, as it never passed its result along to the UI. I am using Q.js (kriw-kowal) and I belive this is where the disconnect is occuring.
Ceasing to listen to 'login', and simply handling my own synthesized event has fixed my issue.
I felt that this was very difficult to explain. If you have feedback about that, and how I can be more clear about what I believe is happening, or if you believe that I have reached wrong or incomplete conclusion, let me know - I'll try to update this answer to be better.
Scenario:
I want to call the logout function if the app is terminated. I'm able to do it using native code:
- (void)applicationWillTerminate:(UIApplication *)app
{
// Run Logout function
}
Problem:
How to do it in IBM mobilefirst hybrid app?
// ************************************************
Edited
First of all, user login in to the app, if the user key in the correct user id and password, it will add the userIdentity into "loginRealm".
WL.Server.setActiveUser("loginRealm", userIdentity);
Next, user closes the apps without logout. So, when the user login for the another time, MFP server will not return any feedback since it will hit this exception:
Cannot change identity of an already logged in user in realm
'loginRealm'. The application must logout first.
Hence, I have to logout the user from MFP server by setting the "loginRealm" to null in adapter;
WL.Server.setActiveUser("loginRealm", null);
The above line of code is in the logout function defined in authentication-config.xml.
The client side device runs this line of code and it will trigger the logout function. Besides, it will reload the App upon success:
WL.Client.logout('loginRealm', {
onSuccess: WL.Client.reloadApp
});
Steps that I've tried:
1) At WlcommonInit() I added WL.Client.updateUserInfo(); and if WL.Client.isUserAuthenticated("loginRealm") return true I will logout the user from server. However, WL.Client.isUserAuthenticated("loginRealm") will always return false. This is because, it needs to take sometime around (30seconds to 2 minutes) for the flag to turn true after WL.Client.updateUserInfo();. So my login still fail and hit the same error.
2) I tried to logout the users during the user click login button. But the app will refresh and return to login page again due to reloadApp. The logout code I get from IBM mobilefirst website. So user need to click and type 2 times in order to login into the main menu.
WL.Client.logout('loginRealm', {
onSuccess: WL.Client.reloadApp
});
Am I doing it wrongly? Or are there any other methods to get WL.Client.isUserAuthenticated("loginRealm") return true instantly after WL.Client.updateUserInfo(); ? Can we remove the reload app line of code in logout function?
I don't think this is doable, because that logout function (in MFP) will require server connectivity (request and response) and if the app is by then killed, I think it's going to cause unpredictable results.
Note though that it seems to be not recommended to use that function anyway? applicationWillTerminate when is it called and when not
What you should do perhaps in order to simulate it, is to logout-on-login, so that it would appear that the app is logged out when opening it. You can extend the duration of the splash screen so that the end-user will not see that s/he is logged in (in case the session was still alive between the closing and re-opening of the app), until really logged out and then you can display the login screen again or any other required screen.
I already know how to launch an app from safari, but is it possible to check if the app is installed before launching? I'm thinking to launch the app store if the app isn't currently installed on the iPhone.
It's not possible to check if app is installed from a web page. You could do it inside an other app by checking if your url scheme can be opened using UIApplication's -canOpenURL: method, but there is no javascript equivalent to this.
However, you can use the following workaround:
<script language="javascript">
function open_appstore() {
window.location='http://itunes.com/';
}
function try_to_open_app() {
setTimeout('open_appstore()', 300);
}
</script>
<a onClick="javascript:try_to_open_app();" href="yourappurl:">App name</a>
This code will set a timeout on the link that will call the open_appstore function if this timeout ends. Since your link is pointed at the app's custom url, Safari will try to open that link and if it can, it will open the app and stop the timer, so AppStore link will not be opened.
If the app link can't be opened, when timer runs out it will display an error popup saying it can't open the page (can't get rid of that), but it will immediately go to AppStore and dismiss that error.
iOS 9 adds a really nice feature that lets your app open a http/s url: Universal Links
In iOS 10 there is a popup saying "Open in [App Name]" when you tap the link and the app is installed. If the user does not tap on "Open" in the given timeout, this solution will use the fallback.
As 300ms is too short to tap anything, this solution always fails on iOS 10.
This worked for me with a similar situation: wherein I wanted to open gmaps app if it was supported - otherwise go to gmap site directly.
function mapLink(addy) {
addy = encodeURIComponent(addy);
var fallback = 'http://maps.google.com/?q=' + addy
, link = 'comgooglemaps://?q=' + addy;
try {
document.location = link;
} catch(err) {
document.location = fallback;
}
}
Seems to work pretty well for my use case.
Update:
If you want to do a new window on fallback, this still allowed the ios error message to pop up. To get around it try this.
try {
document.location = link;
} catch(err) {
window.location.reload(true);
window.open(fallback, '_blank');
}
The Solution from Apple:
From Apple Documentation
https://developer.apple.com/library/ios/documentation/AppleApplications/Reference/SafariWebContent/PromotingAppswithAppBanners/PromotingAppswithAppBanners.html
If the app is already installed on a user's device, the banner intelligently changes its action, and tapping the banner will simply open the app. If the user doesn’t have your app on his device, tapping on the banner will take him to the app’s entry in the App Store. When he returns to your website, a progress bar appears in the banner, indicating how much longer the download will take to complete. When the app finishes downloading, the View button changes to an Open button, and tapping the banner will open the app while preserving the user’s context from your website.
Smart App Banners automatically determine whether the app is supported on the user’s device. If the device loading the banner does not support your app, or if your app is not available in the user's location, the banner will not display.
To add a Smart App Banner to our webpage, include the following meta tag in the head of each page where you’d like the banner to appear:
NOTE: We can also pass the app-argument: like myName,etc.,
Check that Providing Navigational Context to Your App Header in this Page
Updates:
1. Once you have closed the banner that showing up, then that will not be displayed again even though you had that meta tag in our html.
2. To reset that launch the settings App then navigate to General>Resent>Reset all settings
You can simply read the return value from the method -(BOOL)openURL:(NSURL)url*, if it's NO, it means that the target application isn't installed. Following code snipped gives an example using the navigon url scheme:
NSString *stringURL = #"navigon://coordinate/NaviCard/19.084443/47.573305";
NSURL *url = [NSURL URLWithString:stringURL];
if([[UIApplication sharedApplication] openURL:url]) {
NSLog(#"Well done!");
} else {
stringURL = #"https://itunes.apple.com/it/app/id320279293?mt=8";
url = [NSURL URLWithString:stringURL];
[[UIApplication sharedApplication] openURL:url];
}
Thanks to zszen for the correction.