Set start_url in web app manifest based on the URL that was added to homescreen - progressive-web-apps

My site has several subsections. When a user adds the site to their homescreen, I'd like to make sure that the home screen icon launches them into the subsection they were on when they added to homescreen.
I can register a different manifest for each subsection, but this doesn't work for single page apps where there's no page reload. I'm considering storing the subsection in a cookie and then redirecting from a generic start URL based on that cookie.
Is there a better way to do this?

If you remove the start_url from the manifest.json file then it will default to the page user was browsing while adding pwa app to homescreen.
ref : https://developers.google.com/web/tools/lighthouse/audits/manifest-contains-start_url

Have you tried changing the web app manifest url when the user navigates between different subsections?
document.querySelector('link[rel=manifest]').href = '/example-manifest.json';

One solution is for each page do you have a separated manifest with attribute start_url specific to each page.
Editing:
in the HTML for /your_path:
<link rel="manifest" href="/path/to/your_path-manifest.json">
in the HTML for other pages:
<link rel="manifest" href="/path/to/any_other_page-manifest.json">

Had the same problem just now. Here is my solution:
I completely removed the manifest tag from the initial HTML. Instead I now put the manifest together entirely in JS with the start_url set to window.location.href. Then I add it to the head as a Base64 data URL:
const manifest = {
name: 'My App',
short_name: 'My App',
display: 'standalone',
theme_color: '#ffffff',
background_color: '#ffffff',
icons: [
{ src: `${window.location.origin}/path/to/icon.png`, sizes: '192x192', type: 'image/png' },
{ src: `${window.location.origin}/path/to/icon.png`, sizes: '512x512', type: 'image/png' },
{ src: `${window.location.origin}/path/to/icon.png`, sizes: '192x192', type: 'image/png', purpose: 'maskable' },
{ src: `${window.location.origin}/path/to/icon.png`, sizes: '512x512', type: 'image/png', purpose: 'maskable' }
],
start_url: window.location.href
};
const link = document.createElement('link');
link.rel = 'manifest';
link.href = `data:application/json;base64,${btoa(JSON.stringify(manifest))}`;
document.head.appendChild(link);
Seems to work on both Android and iOS.
Note: Since data URLs don't have a root you cannot specify any root-relative URLs within the manifest (e.g. for icons). But it's easy to fix by prepending with window.location.origin. Also the start_url may not be relative. E.g. using just window.location.pathname doesn't work, that's why I am using window.location.href.
Note 2: If you are using a tool to autogenerate the PWA support of your app make sure this tool doesn't generate its own manifest during the build. Usually there should be a config option to disable this. For the Vite PWA Plugin I was able to configure manifest: false.

Had the same problem and tried messing about with the start_url applying many suggestions and none worked. What did work is to remove start_url all together.
Now I'm able to go to any page under and subdirectory and save the page to my phone home screen, when clicking on the save link I taken to the correct page.
Tested this in Chrome, Safari, Firefox and Edge.
Hope that helps.

Related

Is it possible to source a local file resource in an <img>?

I have a need to point my image tags at a directory that is not part of my app.
The use-case is that this is a kiosk app for which the assets are delivered via Dropbox. So, the user will need to configure the app by pointing the fileSystem object at the required Dropbox directory and then the app will use that directory to source its media.
The fileSystem Entry returns a path that looks like:
~/Dropbox/and/so/on/and/so/forth
I'm trying to figure out if there's any way to use that either explicitly
a la
<img src="~/Dropbox/and/so/on/and/so/fort/image.png"/>
or via some hacky alternative like
<img src="file:///users/someuser/Dropbox/and/so/on/and/so/forth"/>
However all the various combinations I've tried produce a broken image - even though when I inspect the element and click on it in the console Chrome is able to view the image as a stand-alone entity, so I know the path is correct.
I feel like I'm overlooking something obvious, but can't find any documentation for how to correctly aim my resources at the file system.
You'd expect that the fileEntry.toURL() method returns the filesystem:..-URL that can be used to directly embed the image in the page. However, that is not the case because of http://crbug.com/148788.
If you're certain that you can always access the filesystem after requesting permissions, the most efficient solution to embed an image from the user's filesystem is to use blob:-URLs. Here is an example without any error handling:
// Within your app's code, somehow get a DirectoryEntry (or FileEntry):
chrome.fileSystem.chooseEntry({
type: 'openDirectory'
}, function(directoryEntry) {
// Assume that the user has selected the directory containing the images.
directoryEntry.getFile('path/to/img.png', function(fileEntry) {
fileEntry.file(function(file) {
var url = URL.createObjectURL(file);
// url looks like "blob:chrome-extension%3A//[extensionid]/[uuid]"
var img = new Image();
img.src = url;
document.body.appendChild(img);
});
});
});
If you don't know the image path in advance, then you could either enumerate the items in the directory using a DirectoryReader (created using directoryEntry.createReader()), or directly prompt for the FileEntry (and use fileEntry.file, etc., to get the blob:-URL).
To try out the previous snippet, use the following as manifest.json
{
"name": "FS App",
"version": "2",
"manifest_version": 2,
"app": {
"background": {
"scripts": ["background.js"]
}
},
"permissions": [
{"fileSystem": ["directory"]}
]
}
background.js
chrome.app.runtime.onLaunched.addListener(function() {
chrome.app.window.create('main.html');
});
main.html
<script src="main.js"></script> <!-- main.js = previous code -->
Create a directory that contains "path/to/img.png", load the app, launch the app and click on the just-created directory that contains that picture. You will see that the image is embedded in the app's document.
You don't use a file:// URL, nor do you use any --allow... exceptions. Once you have a FileEntry, you fetch the binary data from the image and form it into a data URL, which you can use directly as an img src. See my answer to this question: chrome packaged app image access
UPDATE: Given a File object (file), here's the code to set the src property of an image (img):
img.src = webkitURL.createObjectURL(file);
If you have a FileEntry, you can get its File via the file() method.
Are the assets in the user's Dropbox or yours? If they are yours, you should be able to get them using fetch after making them public.

How to display dynamic page description in a shared angularJS page (via google +1 for instance)

I am trying enable the metas in our app for google+ and facebook +1's and I get either nothing, the url of the page, or {{pageDesc}} in the post. Right now I am using a directive that dynamically sets the meta description:
HTML:
<meta meta-description>
DIRECTIVE:
app.directive('metaDescription', [ 'metaData', function(metaData){
return {
restrict: 'A',
replace: true,
template: '<meta name="description" content="{{description}}">',
link: function(scope,element){
scope.metaData = metaData;
scope.description = scope.metaData.pageDesc;
}
};
}]);
When doing this, the google api does not recognize the title and description and just sets the url of the current page and the url of the site as title/description.
I was poking around with prerender.io but I had to disable it because it made the +1 plugin crash.
You have to set those values in the HTML before you render the document. The Facebook/Google/etc bots that crawl the pages don't usually execute JavaScript.

Chrome packaged application - downloading file from Webview

I am working on getting an existing Ajax style web application functional as a Chrome packaged app. The Ajax app is running in a Webview inside the packaged app and is mostly working great.
The Ajax app allows users to upload documents using standard HTML 5 upload and drag/drop. Uploads work fine but downloads are not working.
This is a simplified sample of the logic in the Ajax app. It uses Javascript to handle the click event, performs some logic, and then eventually triggers the download by setting the location of a hidden IFrame.
<html>
<head>
<script type="text/javascript">
function downloadFile(url) {
window.frames['dataTransfer'].location = url;
}
</script>
</head>
<body>
Google<br/>
Download PDF<br/>
Download PDF JS<br/>
<iframe name="dataTransfer" style="width: 0; height: 0; border: none;"></iframe><br/>
</body>
</html>
If you run this in a standard Chrome tab all 3 links work fine. However in a Chrome App only the first 2 links work - clicking the 3rd link does nothing. In the network section of the Developer tools it actually appears to start the download but then is quickly cancelled.
The manifest of the Chrome app allows Webview and the relevant domains involved.
{
"manifest_version": 2,
"name": "Test Download",
"version": "0.1.0",
"permissions": [
"webview",
"<DOMAIN OF THE SAMPLE PAGE ABOVE>",
"https://s3.amazonaws.com/"
],
"app": {
"background": {
"scripts": ["background.js"]
}
},
"icons": {},
"minimum_chrome_version": "28"
}
The Chrome App has some simple newwindow handling in it as well.
window.onload = function() {
var webview = document.querySelector('#app-webview');
webview.src = '<URL TO SAMPLE PAGE ABOVE>';
webview.addEventListener('newwindow', function(e) {
e.preventDefault();
e.stopPropagation();
window.open(e.targetUrl);
});
};
Any suggestions on how to get downloads working (hopefully without requiring significant changes to the Ajax app)?
File downloads from the webview guest are gated by a permissionrequest event per download attempt. The default response is to deny download permission.
Note: The download permissionrequest will not land until Chrome 30 now, and it appears that documentation has not yet been made available. It is generally a stable API though, and it is unlikely to change between now and then.
In order to override this behavior, you need to handle the event and explicitly allow the download to happen. As an example:
var webview = document.querySelector('#app-webview');
webview.addEventListener('permissionrequest', function(e) {
if (e.permission === 'download') {
e.request.allow();
}
});
The event includes additional information (such as the download URL in e.url) in case you want to further filter your grants.
Be aware that this will only permit the download to happen using the regular Chrome file download experience, which isn't necessarily what you'll want from within a packaged app. Your options are limited until the chrome.downloads API is made available to apps.
One possibility is to deny the download request, grab the URL from the event, and manually manage the download process with XHR, the fileSystem API, and whatever UX you want to build.

Async Loading of Facebook Javascript SDK? Placement of channel.php?

"The channelUrl must be a fully qualified URL matching the page on
which you include the SDK."
from the Facebook Developers Javascript SDK Documentation
Okay so I've added my code as shown here:
window.fbAsyncInit = function() {
FB.init({
appId: '*****',
channelUrl: '//www.somehost.com/channel.php', // Channel File
status: true,
cookie: true,
xfbml: true
});
// Additional Init code here.
};
The part of the site that will be loading the FB JS SDK is not on the index page or the root directory of the site where my channel file is located.
So should I have my channel file in //www.somehost.com/channel.php?
Or should I have it somewhere else like in //www.somehost.com/directory/folder/ where the page that is going to load the SDK will be at?
To me it sounds like the latter, but I'm not entirely sure about that since most of the examples I have seen place it in the root directory.
Does placing the channel file in the root directory make it apply to all of the sub directories with pages that will load the SDK within the domain?
It seems a little redundant to me to add a channel file for each subdirectory that has a page in it that will access the sdk (unless this has something to do with security).
All docs refer to it being at root so I think it's fine for it to be there. You will know if it doesn't work if it fails one of the three issues for which it is needed.
The only requirements are that the domains (not the full url) and protocols must match.

How to publish to my own page's wall on Facebook

I just can't find out how to do this.
I'm building a website in scala (on google app-engine) and I made a facebook page for it and created a facebook application. All I want to do is to post to my own page's wall. I don't want to use java facebook api, 'cause I think it's way too much to do such a simple thing, but I really can't find a simple way to do so.
Is there a "low level" facebook api?? something simpler that works on posts and gets like twitter api for example?
Or any idea or alternative way to do so will be appreciated.
Thanks!
Facebook has an API that you can use, but it isn't quite as straightforward as the Twitter API. It would be a bit of overkill to write in support, unless perhaps you are prototyping something for someone else to use.
For an individual case, you might be best served by using Posterous- if you setup a Posterous account linked to your Facebook Profile, emailing facebook#posterous.com with the sender set as yourself will likely be the easiest way to post content to your wall. With this, you can use any SMTP email-capable library that supports either HTML emails or attachments. An added bonus is that you can also cross-post to twitter and a number of other places from Posterous by altering the destination Posterous email.
Incidentally, Posterous also has an API too, but I don't remember off the top of my head if you can redirect where posted materials are sent through the API. I've only used it for image uploads, myself.
Here is a strait forward out of the box wall feed example using Javascript SDK
SDK connection, just change the appId to your Applications own ID.
<div id="fb-root"></div>
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '135669679827333',
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true, // parse XFBML
//channelUrl : 'http://WWW.MYDOMAIN.COM/channel.html', // channel.html file
oauth : true // enable OAuth 2.0
});
if (window!=window.top) {
FB.Canvas.setAutoResize();
}
};
(function() {
var e = document.createElement('script'); e.async = true;
e.src = document.location.protocol +
'//connect.facebook.net/en_US/all.js';
document.getElementById('fb-root').appendChild(e);
}());
</script>
Post Script, notice the to: parameter, change this to the page you wish to post to. You can edit all other fields as needed.
<script language="javascript" type="text/javascript">
//<![CDATA[
function feedthis() {
FB.ui({ method: 'feed',
message: 'Testing Feed',
caption: 'This is the Caption value.',
name: 'Testing JS feed dialog on ShawnsSpace',
link: 'http://shawnsspace.com?ref=link',
to: '391793380398',
description: 'Testing property links, and action links via Feed Dialog Javascript SDK',
picture: 'https://shawnsspace.com/ShawnsSpace.toon.nocolor..png',
properties: [{ text: 'Link Test 1', href: 'http://shawnsspace.com?ref=1'},
{ text: 'Link Test 2', href: 'http://shawnsspace.com?ref=2'},
{ text: 'Link Test 3', href: 'http://shawnsspace.com?ref=3'},
{ text: 'Link Test 4', href: 'http://shawnsspace.com?ref=4'}
],
actions: [
{ name: 'Shawn', link: 'http://ShawnsSpace.com'}
]
});
};
//]]>
</script>
<button onclick="feedthis();">Post to Wall</button>
There are two steps required to do this:
Create a custom Facebook App and add it as a tab to your page
Set this newly added tab as the default when a new user visits your page
Details:
Create a custom Facebook App and add it as a tab to your page
This step is tricky but manageable for an average HTML programmer. To illustrate it best, I will point to a great tutorial on this:
http://how-to-create-facebook-app.koliber.com/
Set the tab as default
As the admin, go to your page
In the upper-right corner click on "Edit Page"
Under the heading "Default Landing Tab", select the tab which
contains the application you created earlier.
Well, I found there is a REST-like api:
This means that our Facebook method calls are made over the internet by sending HTTP GET or POST requests to the Facebook API REST server (http://api.facebook.com/restserver.php) . Nearly any computer language can be used to communicate over HTTP with the REST server.
Documentation here: http://wiki.developers.facebook.com/index.php/API