Many Mobile devices like my android phone have a 'request desktop site' option. I'm in the process of building mobile websites and want to make that native feature work.
What is expected on our end as developers? Is there a GET request for example: leave_mobile=1 or is it the device itself changing the user-agent to trick the application thinking its just another desktop?
I've done some tests on my android devices and read out the user agents and seems like it changes. So What I did to make this native option work was to capture the initial user agent into a session and on each page request compare it with the one being sent.
If the user agent is not the same, revalidate if it is a mobile device and if true overwrite session user-agent with new one. If however the new validation fails, it probably wants to find the desktop version so send a new header redirect.
$DesktopSite = 'www.example.com';
$UserAgent = $_SERVER['HTTP_USER_AGENT'];
if (!isset($_SESSION['use_mobile'])){
$_SESSION['use_mobile'] = 1;
$_SESSION['user_agent'] = $UserAgent;
} else if ($_SESSION['user_agent'] != $UserAgent){ // Check if user-agent has changed
if(!preg_match( /*preg match from http://detectmobilebrowsers.com/ */){
$_SESSION['use_mobile'] = 0;
$_SESSION['user_agent'] = $UserAgent; // Overwrite old user-agent with new one.
header("location: $DesktopSite"); // Send visitor to desktop website.
} else {
// Visitor still seems to be mobile.
$_SESSION['use_mobile'] = 1;
$_SESSION['user_agent'] = $UserAgent; // Overwrite old user-agent with new one.
}
}
If you enter the mobile website on a desktop for the first time, it will not send you back to the desktop site because it will create the session first. This way you can check the mobile site on a desktop as well instead of being send back. If however you change your user-agent, you will be revalidated and redirected on fail.
Works perfectly. Hope this may help anyone in the future.
Related
I am searching for a test automation tool that supports the following test case:
start an app on the smartphone
click on a button; the click on the button starts the browser and opens a web page in the browser, on the smartphone of course
enter some data in the browser
return to the app: the entered data must be visible now in the app
I have seen many test automation tools, that support app testing and browser testing. But there I have seen only situations where the browser is opened on the computer where the test automation tool runs; or cases where the browser is started separately on a smartphone.
Does anyone know a tool that supports testing the described communication between the app and the browser which was started by the app?
This can be done in the standard automated UI testing that comes with Xcode, XCUITest (i'm assuming the Android equivalent can do the same). I'm a fan of using the inbuilt stuff as you get full access to Swift/Objective-C and don't have to deal with any additional, buggy dependencies
E.g. I had a settings screen in an app that had multiple links to external resources. I had an automated test that tapped the buttons, waited a few seconds, then verified that safari contained the correct URL, then returned to the app.
Your usecase will obviously be more involved than mine, but here is a sample of navigating from app -> Safari -> interact with safari -> return to app
func test_ExternalLinks() {
// Hold onto a reference of our app that we are testing, and safari installed on the phone
let app = XCUIApplication()
let safari = XCUIApplication(bundleIdentifier: "com.apple.mobilesafari")
// Query to get safari URL textfield
let urlTextField = safari.textFields["URL"]
// Navigate to settings screen
...
...
// Tap "About" button in our app
app.tables.staticTexts["About"].tap()
sleep(2)
// Tap URL bar so we can examine the full URL
safari.buttons["URL"].tap()
urlTextField.tap()
// Extract URL and compare to known value
var url = urlTextField.value as! String
XCTAssert(url == "https://...../about/", url)
// Return to our app
app.activate()
sleep(2)
}
Our production Android application uses Chrome Custom Tabs for OAuth login
It was working fine yesterday when Chrome version was 61.0.3163.98
Following an overnight update of Chrome to 72.0.3626.76 the Login process gets stuck in the embedded browser and the user is presented with a blank white screen.
If we uninstall the Chrome update the login starts to work again
What has changed with Chrome and/or Chrome Custom Tabs that breaks our login process?
If I switch my default browser to Firefox my apps login works fine.
In fact if I change default browser to anything other than chrome it works fine, even Opera works, although Opera doesnt show an embedded browser.
It also works when I uninstall the Chrome update and revert back to chrome version 61.0.3163.98
Further Details:-
Step 1). Load URL with prompt=none and my custom scheme Redirect URL.
Step 2). My App receives a NEW INTENT containing the auth code.
Step 3). I attempt to access my back end APIs with this code, which fails with 400
Step 4). Load URL prompt=login and my users are presented with a sign in screen where they enter their credentials and click on the Sign In button.
Step 5). NOTHING HAPPENS, the user is presented with a blank screen, my app does not receive a NEW INTENT.
Heres the code I employ to open the Login URL via a Chrome Custom Tab
private void openCustomTab() {
codeVerifier = generateRandomCodeVerifier();
checkCodeVerifier(codeVerifier);
codeChallenge = deriveCodeVerifierChallenge(codeVerifier);
CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(this, getURL(PROMPT_NONE));
}
The above code loads the URL with prompt=none and it also specifies my custom scheme redirect url.
My Android app receives a New Intent in onNewIntent that contains an authCode, I attempt to retrieve an access token with this authocode which fails with 400.
I then use custom Tabs to load a second URL with prompt=login as follows:-
final CustomTabsIntent.Builder builder = new CustomTabsIntent.Builder();
builder.setToolbarColor(Color.BLUE);
final CustomTabsIntent customTabsIntent = builder.build();
customTabsIntent.launchUrl(SignInActivity.this, getURL(PROMPT_LOGIN, authCode));
By loading this URL with prompt=login the user can enter their credentials and click on the Sign In button.
Its at this point the Chrome Custom Tab gets stuck.
here are the network calls I capture using Stetho, the last call made is authorization.ping that shows as cancelled
I have found a resolution for this issue as follows:-
I added an additional prompt of "consent" to the existing prompts of "none" then "login".
Now the user see a consent screen titled
oauth.approval.page.template.title
where the user sees a list of choosable options including
ACCESS TO YOUR DATA
SIGN IN WITH OPENID CONNECT
OPENID CONNECT PROFILE SCOPE
OPENID CONNECT EMAIL SCOPE
at the bottom of this screen theres two options
oauth.approval.page.template.allow
oauth.approval.page.template.dontAllow
when the user selects
oauth.approval.page.template.allow
they can now proceed into the android app.
The only issue is the user sees this approval screen whenever they log in
I have recently answered this same question, I believe the update with chrome adds some security layer. I also had same issue before with different browser (stock browser that comes with different non-officials Custom ROMS) and I think we're not safe in case other browsers implement the same behavior.
To avoid all these problems, I would suggest that you implement a staging page that will serve to handle all your OAuth2 redirects.
This solution also has the advantage of avoiding for the user to "Allow" login every time.
You can find a detailed answer here: How to implement OAuth single Sign In/Sign Out with Chrome Custom Tabs
The only change that has been made on that update is the break/removal of HPKP ( HTTP-Based Public Key Pinning)
HTTP-Based Public Key Pinning (HPKP) was intended to allow websites to send an HTTP header that pins one or more of the public keys present in the site's certificate chain. Unfortunately, it has very low adoption, and although it provides security against certificate misissuance, it also creates risks of denial of service and hostile pinning. For these reasons, this feature is being removed.
You are getting the 400 Bad request because of that, Thats just my guess.
If all goes well, the Bundle contains a valid token in the KEY_AUTHTOKEN key using token = bundle.getString(AccountManager.KEY_AUTHTOKEN); from the AccountMangerCallback and you're off to the races
Authentication with OAuth2 services has been changed on developer.android.com, it is required to request an auth token again, some of the authenticators are requiring a direct interaction with the user before giving a valid token.
try and run AccountManager or whatever API you're implementing to get KEY_INTENT before you get clientID, clientSecret, granting type, or your redirectURI
check the following link and adopt any new implementations: https://developer.android.com/training/id-auth/authenticate
We have an android website which opens in webview(ie from app) and also in web browser.
In both cases we have to show different behaviour. Is there any way to distinguish whether the request is from app webview(which internally opens the application on native browser) or direct browser request.
We cannot depend on user agent as we cannot update client side.
I want to do something like this:
if(webview)
{}
else if(browser)
{}
Its a high priority issue, so anybody having any clue to resolve this, please post ASAP!
Set a user Agent String in Webview and get it in your code
yourWebView.getSettings().setUserAgentString("Some user agent String to identify");
See this answer it explains how to do it.
if(window._cordovaNative) {
// its a web view
} else {
// its a web browser
}
All http requests sent through a webview have the header bellow present. You can use this to detect where you got the request from
X-Requested-With: the.app.packageName
Not really sure how to correctly describe this so hopefully some of you know what I mean.
Our client is getting a mobile app for thier site, hopefully soon, and I have noticed on android devices and sure they probably exist on iphones too, a popup to inform you that said site has an app. I have seen it on forums that support tapatalk as well as the sammobile.com website. Its a small message and an "ok" and "cancel" button, ok takes you to the app in the market.
Googles only really helpful when you know or at least can correctly describe what you are looking for.
Does anyone know
A) Do iPhones also have this feature and
B) how would I go about triggering such a popup/notification?
Using some infor from a java push trigger as well as a few other Stacks I put this together.
if (/Android|iPhone|BlackBerry/i.test(navigator.userAgent)) {
var url = confirm("Would you like to download our mobile application?");
if (url === true) {
var url = window.location.href = 'http://www.google.com';
url.show();
}
}
Will test for the 3 devices mentioned, if so will create a confirmation box for which confirmation will direct the user to another url.
I need to develop a webapp that needs to know the unique identifier (mac address, for example) of the smartphone that is using it. Most of the methods I'm looking at are cookie/IP based but this is not useful in my case scenario as I'm trying to match the use of a native Android app to the use of its counterpart webapp.
So, is this even possible? If it is, which technology should I use for the webapp development?
Thanks!
You could leave a UUID cookie with the user. When they hop on the app, check the UUID against your list of previous visitors. If you find it, they are not unique.
Edit: by cookie, I mean you could just leave a UUID string file on the user's sd card or store it in a preference of the app.
Presumably the application is installed from the Android Market, so you can't match a site cookie passed in the download URL (or, doubtless, that's exactly what you'd do).
That being the case, can you use URL rewriting? Or at least insert a unique ID into each access to your website, doubtless corresponding to a cookie. Then, when the user downloads the application and runs it the first time it can access the Browser history and look for this unique ID, store it (if it exists) and include it with subsequent server requests.
int occasions=0;
String sessionId = null;
while (cursor.moveToNext()) {
String urlVisited=cursor.getString(cursor.getColumnIndex(BookmarkColumns.URL));
Log.d("Match",urlVisited);
if (urlVisited.contains("www.mysite.com") && urlVisited.contains("MYUNIQUEID")) {
//There's a unique ID. Trim it out of the query string.
sessionId=urlVisited.substring(urlVisited.indexOf("MYUNIQUEID")+10);
if (sessionId.indexOf('&')>-1) {
sessionId=sessionId.substring(0,sessionId.indexOf('&'));
}
occasions++;
}
}
Log.d("Match","occasions="+occasions);
if (sessionId!=null) {
getSharedPreferences("com.mysite", MODE_PRIVATE).edit().putString("SITEID", sessionId);
}
This seems like a bit of a hack - possibly because it is - but it should work and I can't think of another sure way to link browser and custom client requests. Of course if the user cleans his history or cookies before downloading and running the application then the above will not work.
I hope that's of some help.