Branch.io: javascript detect whether mobile app is installed - javascript

I have a web page where I want a particular link on a page to open our native mobile app if the app is installed, and if not, do what it is currently doing (which submits a form).
Note: I think this is different than a smart banner - I don't want the banner on this page. I just want the normal app flow if there is no mobile app.
I have integrated branch-sdk in the web page and in my ios app. I have successfully set up a deep link from the web page to the iOS app (code not shown), but I am not getting results I expect when sniffing for whether the app is installed.
Here's the code in the <head> of my webpage:
branch.init('MY_KEY', null, function(err, data) {
console.log('init...');
console.dir(data);
});
branch.setIdentity('test-user', function(err, data) {
console.log('identity...');
console.dir(data);
});
branch.data(function(err, data) {
console.log('data...');
console.dir(data);
})
Here's my code in application(_:didFinishLaunchingWithOptions:) in the iOS side:
//Initialize Branch
if let branch = Branch.getInstance() {
branch.setDebug()
branch.initSession(launchOptions: launchOptions, andRegisterDeepLinkHandler: { params, error in
if let params = params, error == nil {
// params are the deep linked params associated with the link that the user clicked -> was re-directed to this app
// params will be empty if no data found
// ... insert custom logic here ...
print("params: %#", params.description)
}
})
branch.setIdentity("test-user")
} else {
readerLog.error("failed to initialize branch")
}
Every time I load the webpage (even after loading it, and following the deep link), I get the following as output in the console. Note that +isfirstsession is true, and the hasApp property is null:
[Log] init... (localhost, line 18)
[Log] Object (localhost, line 20)
data: "{\"+is_first_session\":true,\"+clicked_branch_link\":false}"
data_parsed: {+is_first_session: true, +clicked_branch_link: false}
has_app: null
identity: null
referring_identity: null
referring_link: null
[Log] identity... (localhost, line 23)
[Log] Object (localhost, line 25)
identity_id: "352945822373397525"
link: "https://nlfd.app.link/?%24identity_id=352945822373397525"
link_click_id: "352947632809063724"
referring_data: "{\"$one_time_use\":false,\"+click_timestamp\":1485387510,\"_branch_match_id\":\"352945819276765390\",\"_t\":\"352945819276765390\",\"referrer\":\"link_clic…"
referring_data_parsed: Object
session_id: "352945822337503746"
[Log] data... (localhost, line 28)
[Log] Object (localhost, line 30)
data: "{\"+is_first_session\":true,\"+clicked_branch_link\":false}"
data_parsed: null
has_app: null
identity: null
referring_identity: null
referring_link: null
What am I doing wrong? I was hoping I could just look at the has_app property after init or after setting the identity. Is it incorrect to assume that has_app would return true in this case? Is there a more appropriate way to do what I want to do?

Alex from Branch.io here:
Unfortunately the has_app parameter is not especially reliable. It's good enough for switching a button between displaying an Open or an Install label, but ideally you don't want to use it for functional things. This is a limitation caused by iOS: Apple doesn't allow web pages to query for which apps are installed on a device (for obvious privacy reasons), so Branch has to rely on cookie matching. This means if we can't match the cookie, or haven't seen the user recently, or the user clears their device cache, or the user has uninstalled the app since the last time Branch saw them, the value of has_app will be incorrect.
HOWEVER, even though Apple doesn't allow web pages to query access this data, iOS itself can still act on it. Universal Links do exactly this — when the user opens a Universal Link (which includes Branch links, assuming you got all the configuration done), the app will open if it is installed. If it is not installed, the user will be sent to the URL of the link. You just need to put a Branch link behind that button.
Note however that this doesn't work for form submission buttons, so you would need to come up with some UX workaround for this. Or you might be able to find a way to submit the form after a delay if the app doesn't open, by using a Javascript timer.

Related

Liferay 7: Retrieved custom field value using javascript api jsonws return java.lang.NullPointerException

I'm very new to liferay, I've created a page custom field using 'control panel > configuration > custom fields > page'. My goal is to retrieve the value from the page custom field and display the value in my custom portlet. One of the methods I've tried is using ExpandoValue/get-data API from the liferay json web service and this API is generated from localhost:8080/api/jsonws. Below is the generated javascript API:
Liferay.Service(
'/expandovalue/get-data',
{
companyId: themeDisplay.getCompanyId(),
className: 'com.liferay.portal.model.Page',
tableName: 'CUSTOM_FIELDS',
columnNames: 'pageDetail',
classPK: themeDisplay.getUserId()
},
function(obj) {
console.log(obj);
}
);
However, this api throws me an error: java.lang.NullPointerException. I'm thinking that this error occurs due to the permission given to the custom field. So, I've ticked View and Update permissions for Guest. But the issue persists.
My question is what triggered this error and how to fix it and is there any other solution I can use to retrieve the value from the page custom field?
Thanks in advance.
Edit
I had misunderstanding in assigning the attributes for the api and here is the new api as suggested by Olaf.
Liferay.Service(
'/expandovalue/get-data',
{
companyId: 20115,
className: 'com.liferay.portal.kernel.model.Layout',
tableName: 'CUSTOM_FIELDS',
columnName: 'details',
classPK: themeDisplay.getLayoutId()
},
function(obj) {
console.log(obj);
}
);
It works fine. However it only took the default value but not the value assign for that particular pages.
If memory serves me right, the stock remote API can't be used by unauthenticated users, but requires at least a logged in user (on top of the regular permissions of course).
You can test for this by accessing the API from logged in accounts with the same permissions. If it works there, then this is what you're running into.
However, when I interpret the call in your question correctly, the current user id would be the primary key for the custom field that you're looking at (looking at your classPK value). For a custom field on the page, I'd have expected a page id (layoutId in Liferay-API-terms). And while I'm seeing this, I notice com.liferay.portal.model.Page in your snippet. I've not seen that class, and pages can rather be found in com.liferay.portal.kernel.model.Layout (Assuming Liferay 7.1)
This makes me wonder what you're trying to achieve here - are you rather looking for a user-specific field (that would then be a custom field on the user) or really a page-specific field? Anyways - as this is an answer, not a comment, it might give enough hints to try out and come closer to a solution.

Clear Chrome browser logs in Selenium/Python

I have a large application and I am using Headless Chrome, Selenium and Python to test each module. I want to go through each module and get all the JS console errors produced while inside that specific module.
However, since each module is inside a different test case and each case executes in a separate session, the script first has to login on every test. The login process itself produces a number of errors that show up in the console. When testing each module I don't want the unrelated login errors to appear in the log.
Basically, clear anything that is in the logs right now -> go to the module and do something -> get logs that have been added to the console.
Is this not possible? I tried doing driver.execute_script("console.clear()") but the messages in the console were not removed and the login-related messages were still showing after doing something and printing the logs.
State in 2017 and late 2018
The logging API is not part of the official Webdriver specification yet.
In fact, it's requested to be defined for the level 2 specification. In mid 2017 only the Chromedriver has an undocumented non-standard implementation of that command.
In the sources there's no trace of a method for clearing logs:
The public API Webdriver.get_log()
which references internal Command names
which translate to acutal requests in RemoteConnection
Possible Workaround
The returned (raw) data structure is a dictionary that looks like this:
{
u'source': u'console-api',
u'message': u'http://localhost:7071/console.html 8:9 "error"',
u'timestamp': 1499611688822,
u'level': u'SEVERE'
}
It contains a timestamp that can be remembered so that subsequent calls to get_log() may filter for newer timestamps.
Facade
class WebdriverLogFacade(object):
last_timestamp = 0
def __init__(self, webdriver):
self._webdriver = webdriver
def get_log(self):
last_timestamp = self.last_timestamp
entries = self._webdriver.get_log("browser")
filtered = []
for entry in entries:
# check the logged timestamp against the
# stored timestamp
if entry["timestamp"] > self.last_timestamp:
filtered.append(entry)
# save the last timestamp only if newer
# in this set of logs
if entry["timestamp"] > last_timestamp:
last_timestamp = entry["timestamp"]
# store the very last timestamp
self.last_timestamp = last_timestamp
return filtered
Usage
log_facade = WebdriverLogFacade(driver)
logs = log_facade.get_log()
# more logs will be generated
logs = log_facade.get_log()
# newest log returned only
This thread is a few years old, but in case anyone else finds themselves here trying to solve a similar problem:
I also tried using driver.execute_script('console.clear()') to clear the console log between my login process and the page I wanted to check to no avail.
It turns out that calling driver.get_log('browser') returns the browser log and also clears it.
After navigating through pages for which you want to ignore the console logs, you can clear them with something like
_ = driver.get_log('browser')

Google Sharing API Leads to 500 Error and "Sharing is Unavailable" Message

I am attempting to set up the sharing ability on a web application that I am making. I have followed the steps on Google's Drive Sharing Instruction Page to the best of my ability. However, when I click the button, I get the expected popup, but with the message "Sorry, sharing is unavailable at this time. Please try again later."
The code I have is slightly different, as the init function name is being used elsewhere. The code I have is:
function initializeGoogleApis() {
/*
self._shareClient = {
'showSettingsDialog': function() {
devConsole.warning(0, "The sharing ability has not yet been implemented.");
}
};*/
gapi.load('drive-share', function() {
self._shareClient = new gapi.drive.share.ShareClient();
self._shareClient.setOAuthToken(self.clientId);
self._shareClient.setItemIds(self.realtimeUtils.getParam("id"));
});
}
Note the commented section. I had this to insure that the 'share' button on my page is loaded properly and calling the function, which it is. As explained in the title, when I click the button, I get a 500 error in the console.
At the bottom of the Google page listed above, it says the following:
The user is signed in to Google --> I have done this
The user has installed your app --> I don't know about this. For all other functionality, I only have to visit the site, so I am not sure what the difference here is.
The URL of the page that launches the dialog must have the same origin as the Open URL registered for the app --> I think I have this done. I followed the link on the page (here) and verified ownership.
I am also testing on the actual host, not on localhost as it states this will not work.
All the same, I get the following error:
GET https://drive.google.com/sharing/share?id=xxxxx_xxxxxxxxxx8&fore…
d=false&client=postMessage&embedOrigin=http://www.example.com 500 ()
_.k.$l # cb=gapi.loaded_0:651
_.k.S # cb=gapi.loaded_0:651
_.k.Ql # cb=gapi.loaded_0:794
ys.kc # cb=gapi.loaded_0:791
Ts.OV # cb=gapi.loaded_0:822
Zs # cb=gapi.loaded_0:814
FM # cb=gapi.loaded_0:818
Ts.Ph # cb=gapi.loaded_0:818
pt.Na # cb=gapi.loaded_0:829
onclick # ?id=xxxxx_xxxxxxxxxxxxxxxxxxx:97
Any help would be appreciated
It looks like you are passing in your clientID instead of your OAuth token.

Firefox - displaying web notifications from extension/addon

I'm building Firefox addon (with addon-SDK) and I'd like to display desktop notification to a user.
There is Notification object but it doesn't seem to work from addon code (background page). There is no error etc, but no dialog for permissions is displayed, so no notifications can be displayed. I've tried of course adding permissions/desktop-notifications but no effect.
Edit: pasting sample code I've tried (the code is located inside callback function for socket.io event. Event is received properly, but no notification is displayed, or request for permission.
Notification.requestPermission( function(status) {
console.log(status); // notifications will only be displayed if "granted"
var n = new Notification("title", {body: "notification body"}); // this also shows the notification
});
I've also found alerts service this one works. However alerts disappear quite fast (too fast for me) - edit: that's the way it works - so guess no code sample needed, as I don't see any option to make them last longer.
Is there any way to display chrome like notifications on Firefox? (chrome.notifications.create) Or at least use web notifications object from within the addon?
If you're using the add-on SDK, you're looking at the wrong docs. Here are the notification docs.
You create a notification like so:
var notifications = require("sdk/notifications");
notifications.notify({
title: "Jabberwocky",
text: "'Twas brillig, and the slithy toves",
data: "did gyre and gimble in the wabe",
onClick: function (data) {
console.log(data);
}
});
All the docs you look at should be a subset of developer.mozilla.org/en-US/Add-ons/SDK.

Facebook auth.sessionChange event and page changes

I am creating a Facebook Canvas application, and I am following more or less the demo app.
As in the demo, I can get the user data from the signed_request which is POSTed to my site on the first page load. Moreover, as suggested in the demo, I use the following snippet to reload the page on user changes:
var Config;
function facebookInit(config) {
Config = config;
FB.init({...});
FB.Event.subscribe('auth.sessionChange', handleSessionChange);
...
}
function handleSessionChange(response) {
if ((Config.userIdOnServer && !response.session) ||
Config.userIdOnServer != response.session.uid) {
goHome();
}
}
function goHome() {
top.location = 'http://apps.facebook.com/' + Config.canvasName + '/';
}
Here Config is an object which is populated with info from the server.
The problem appears when the user navigates the application using a link. If I use AJAX, the page is not actually reloaded and everything works fine. But if I use a standard link, the user comes to another page of my application with a standard GET request. In this case, I do not know how to get the info about the user, so Config.userIdOnServer is undefined and a page reload is triggered.
Of course I can avoid this by removing the call to handleSessionChange, or by making a one-page app with only AJAX links, but I feel I am missing something basic about the Facebook flow.
My fault, I had problems in retrieving the cookie with the user identity for subsequent requests.

Categories