How to cause a chrome app to update as soon as possible? - google-chrome-app

Deploying a chrome packaged app and publishing updates on the chrome web store allows users to automatically receive application updates. There are situations where you want to know if the running application is the most current or not, and updating it. E.G.:
Just keeping the user on the most recent version.
Detecting a mismatch between the application and server side APIs, and requiring the client side application to update to use new server side APIs.
Documentation for chrome.runtime.requestUpdateCheck() offers a status of "throttled", "no_update", "update_available", but doesn't indicate what to do if a newer version is required.

Install a listener for chrome.runtime.onUpdateAvailable, which fires when the new .crx file has been downloaded and the new version is ready to be installed. Then, call chrome.runtime.requestUpdateCheck:
chrome.runtime.onUpdateAvailable.addListener(function(details) {
console.log("updating to version " + details.version);
chrome.runtime.reload();
});
chrome.runtime.requestUpdateCheck(function(status) {
if (status == "update_available") {
console.log("update pending...");
} else if (status == "no_update") {
console.log("no update found");
} else if (status == "throttled") {
console.log("Oops, I'm asking too frequently - I need to back off.");
}
});

Depending on your application, when an update is detected you may want to use something like setTimeout and call chrome.runtime.restart() or chrome.runtime.restart() later

According to the Google Chrome documentation you need to have
chrome.runtime.onUpdateAvailable.addListener(function(details) {
chrome.runtime.reload(); // To restart the chrome App instantaneously
});
But this take time to reflect JS changes into the chrome because background.js loaded into the background and it needs to be unloaded and loaded again
To cop this situation you need to include
chrome.runtime.onInstalled.addListener(function(details) {
chrome.runtime.reload();
});
as wel.
onInstalled called whenever google extension installed first time (fresh installation), google extension updated or google chrome updated.

Related

Flutter (web) - how to reload the Flutter PWA

This is the similar question (with wrong title): Flutter Web - How to reload currently Active Page
Running the Flutter web app as PWA I need to allow users to initiate refresh and thus update the (web) app.
Unfortunately import 'dart:html' as html; is not allowed anymore when having the same codebase for web and mobile native apps. So following code is not the option:
RaisedButton(
child: Text("Update me"),
onPressed: () {
if (kIsWeb) html.window.location.reload();
},
),
What is the correct approach?
EDIT:
I have managed to use 'dart:js' in the same codebase for pwa and mobile using conditional imports. This means I can call JavaScript from within the Flutter code. Unfortunately location.reload(true); does not reload the PWA.
Ideally I would have the Flutter approach for the PWA reload / update or JavaScript workaround.
EDIT2:
The whole issue is within the PWA handling of refresh button / window reload.
Unfortunately service worker's skipWaiting() can be called only from within service worker ( https://developers.google.com/web/fundamentals/primers/service-workers/lifecycle#skip_the_waiting_phase )
The correct approach seams to be sending the skipWaiting message to the new instance of the service worker.
However skipWaiting is not yet fully supported on some browsers (iOS?) so the safer approach seams to be just unregistering the worker...
I ended up using following to stop the worker and reload.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistration().then(swr => {swr.unregister().then(
() => {location.reload(true)}
)});
} else {location.reload(true)}
Related:
Access service worker skipWaiting from within App build with Webpack+Workbox
https://medium.com/#nekrtemplar/self-destroying-serviceworker-73d62921d717
https://redfin.engineering/how-to-fix-the-refresh-button-when-using-service-workers-a8e27af6df68
https://deanhume.com/displaying-a-new-version-available-progressive-web-app/
Flutter 2.10.3
In the newest version of Flutter (2.10.3 at the time of writing this), PWAs will automatically update when the serviceWorkerVersion changes in your index.html file.
From this issue, Jonah Williams comments:
"The app will update after the new version has been downloaded and the page revisited."
You can read more about general PWA support by Flutter here. For the pull request that added server worker support, see this.
If you want to allow users to manually fetch a new version of your app, you can use the universal_html package which works on all platforms.
import 'package:universal_html/html.dart' as html;
onTap: () {
html.window.location.reload();
},
Keep an eye on this issue for an improvement to how server worker caching is handled.
A work around would be to navigate to your apps entry point route '/'
`Navigator.of(context).pushNamedAndRemoveUntil(
'/,
(Route<dynamic> route) => false
);`
I maintain a set of web versions myself. When I upgrade my web application, I will upgrade the version level. Every time I start homePage, I will request the version number of the remote configuration to match the version number of the current PWA application. When the local version number is lower than the remote version number, I will refresh
//pubspec.yaml universal_html: ***
import 'package:universal_html/html.dart' as html;
getWebVersion() async{
var res= await dio.get(web_version);
if (locaVersion < res.version) {
html.window.location.reload();
}
}

How can I determine if the current platform is a native app or web in Capacitor?

In Cordova you had immediate access to process.env.CORDOVA_PLATFORM is there something similar in Capacitor?
I'm looking to conditionally load some functions on startup and don’t want to block rendering waiting for async Device.getInfo to come back.
For example I want to determine immediately wether to import a script that make's native keyboard modifications, but I don't want to import this script if we are running on web
try {
const { Keyboard } = Plugins
Keyboard.setAccessoryBarVisible({ isVisible: true })
} catch (error) {
// Keyboard isn't available on web so we need to swallow the error
}
I'm using vue-cli
The answers so far are all correct, if you take a look into the Capacitors source code, there a few ways available, which can be used (but are undocumented for now):
Capacitor.getPlatform(); // -> 'web', 'ios' or 'android'
Capacitor.platform // -> 'web', 'ios' or 'android' (deprecated)
Capacitor.isNative // -> true or false
Be aware, that the method Capacitor.isPluginAvailable('PluginName'); only returns if the plugins is available or not (obviously) but important here, it does not tell you, if the method you want to execute after checking the availability is for your platform available.
The documentation of the Capacitor Plugins is not completed (yet).
Example (code), for the plugin StatusBar:
// Native StatusBar Plugin available
if (Capacitor.isPluginAvailable('StatusBar')) {
// Tint statusbar color
StatusBar.setBackgroundColor({
color: '#FF0000'
});
}
This would result in an error on iOS, since this method is not available there, on Android it works fine so far.
That means, that you need to implement a check of the Plugin and Platform combination by yourself (for now), may this will be improved in the future by Ionic / Capacitor itself.
Something like:
// Native StatusBar available
if (Capacitor.getPlatform() === 'android' && Capacitor.isPluginAvailable('StatusBar')) {
// Tint statusbar color
StatusBar.setBackgroundColor({
color: this.config.module.GYMY_MODAL_STATUSBAR_HEX_STRING
});
}
One more thing, you are not able to check, whether the method exists within this plugin (f. e. for the code above setBackgroundColor) as it is available, but throws an error (Error: not implemented) on a platform, which does not support it.
Hope I could help some of you guys.
Cheers
Unkn0wn0x
There is also the property Capacitor.isNative which you could use to determine whether the WebApp is running in Capacitor or in the Web.
https://github.com/ionic-team/capacitor/blob/master/core/src/definitions.ts
Update: In Capacitor V3 you can use Capacitor.isNativePlatform() for this.
https://capacitorjs.com/docs/v3/core-apis/web#isnativeplatform
As of Capacitor 3, you can use the following method to determine if it's running on a native device ("iOS" - "Android") or not ("web").
import { Capacitor } from '#capacitor/core';
if(Capacitor.isNativePlatform()) {
// Platform is mobile
} else {
// Platform is not mobile
}
Official documentation link. https://capacitorjs.com/docs/core-apis/web#isnativeplatform
Found it undocumented: Capacitor.platform
Capacitor.platform could be for example web ios android
Also if you wanted to know if you were running native before loading Capacitor, i.e you wanted to reduce bundle size by not including Capacitor on the web.
window.origin.includes('capacitor://')
You can now use Capacitor.isPluginAvailable('plugin name') to make this check, e.g., :
import { Capacitor, Plugins } from '#capacitor/core';
const { Keyboard } = Plugins;
...
const isAvailable = Capacitor.isPluginAvailable('Keyboard');
if (isAvailable) {
Keyboard.setAccessoryBarVisible({ isVisible: true })
}
You can see all of those on official doc here: https://capacitorjs.com/docs/basics/utilities#getplatform
if (Capacitor.getPlatform() === 'ios') {
// do something
}
if (Capacitor.isNative) {
// do something
}
I would say Device.getInfo() is the only reliable way of checking device's platform in capacitor based project.
Because the implementation of getPlatform(), Capacitor.platform is based on user agent of ui client. That means, if you opened your app on web and select developer tools then select mobile view, in this case it identify your platform as ios or android depending on which one you selected in dev tools instead of 'web'

I want to give force update feature in my app for android users

I am using ionic 3 for these and i need to give a force update feature for android users.
can i able to do it with-->
like first compare current play store version and user version and then set
a page for those users who don't have the updated version and force user's
for update the app, can i use file transfer plugin for update the app.
what approch is right?
You can use following plugins to verify that updates is available in playstore.
cordova-plugin-app-update
You should first host an XML file on your server with the following data in it:
<update>
<version>302048</version>
<name>APK Name</name>
<url>https://your-remote-api.com/YourApp.apk</url>
</update>
And then check with
constructor(private appUpdate: AppUpdate) {
const updateUrl = 'https://your-remote-api.com/update.xml';
this.appUpdate.checkAppUpdate(updateUrl).then(() => { console.log('Update
available') });
}
More details available here
Did you try this with release build package ?

Delete Apk after app installation

I am working on an app in which I have to restrict the user to share the apk personally. One can download it but should not be allowed to share the App (apk) personally via bluetooth etc.
I searched and read alot about the same issue but didn't find a complete answer. I have tried the below.
How to get the file *.apk location in Android device
Download, Installing and Delete .apk file on android device programmatically from a website other than marketplace
What I have understood from above is that the easy way to do this is to delete the apk file from the User's device after the app is installed. (I also know that user may generate this apk again via root access but that is fine as at-least I will be able to restrict not all but many).
Now what I have tried, I am registering a Broadcast receiver and in my onReceive() method I have the below,
PackageManager pm = getPackageManager();
for (ApplicationInfo app : pm.getInstalledApplications(0)) {
if (myPackage.equalsIgnoreCase(app.packageName)) {
apkPath = app.sourceDir;
break;
}
}
Log.d("Package", myPackage + " - APK - " + apkPath);
if (intent.getAction().equals("android.intent.action.PACKAGE_ADDED")) {
File sdcard = Environment.getExternalStorageDirectory();
File file = new File(sdcard, apkPath);
file.delete();
}
But this does nothing as I am not aware of the IntentFilter I should use to register this.
Can any one guide me on what is the next step? and in case I am completely on a wrong land then help me achieve the above?
Any help will be appreciated. :)
On later versions of Android, some (all?) broadcasts aren't sent to an app until it has been manually opened at least once. This is a security feature that can't be circumvented.
As far as I know, It is not possible to listen the installation complete broadcast event. Android Api having Broadcast Action: "ACTION_PACKAGE_ADDED" But newly installed package does not receive this broadcast. Source : Here
My suggestion is check in your first launcher activity and delete the apk.
You can use the Android App Licensing Service here.
Refer http://developer.android.com/google/play/licensing/index.html and the implmentation here http://developer.android.com/google/play/licensing/adding-licensing.html.
This will ensure that the apk cannot be shared(making it protected) using any of the apps available on market.
Sorry for bad english.
Here my solution not actual code:
1) set your broadcastreciver when any new application is install in your device.
2) When your broadcastreciver is call, that time you write code in onRecive() method
check the your app package if install or not
private boolean isPackageInstalled(String packagename, Context context) {
PackageManager pm = context.getPackageManager();
try {
pm.getPackageInfo(packagename, PackageManager.GET_ACTIVITIES);
return true;
} catch (NameNotFoundException e) {
return false;
}
}
using this method or any
if you get true means your application is install
3) if you get true from isPackageInstalled("com.download.app", context) method
that time delete apk file from your SD card or any loaction in device
if you more clarification i will be explain.
i used the idea of creating a folder when the app runs for the first time .if it doesnot exist , delete the apk. if the folder exists , then the apk has already been deleted.
This folder will be deleted on its own if the app is unstalled.
public static String link = Environment.getExternalStorageDirectory()
.getPath() + "/Android/data/YourAppPackageName/";
//check if its running for the first time
File f = new File(link);
if (f.exists()) {
File f1 = new File("/data/app/YourAppPackageName.apk")
if(f1.exists()){f1.delete();}
}
else {
f.mkdirs();
}
You can also use the HockeyApp product and distribute using the Android App that they provide, as well as enable the "restriction" features. I'm pretty sure that will do what you need without having to write extra code.

Soundcloud record flash plugin don't work with current version of chrome under macOS

this record plugin stops to work for us with current version of chrome under macOS
Chrome: Version 23.0.1271.97
MacOS: 10.8.2
http://connect.soundcloud.com/examples/recording.html
how to reproduce:
click record
allow using your microphone
-> recording don't start
(In fact sometimes it works (20% of cases for me))
and also sometimes there is an error in console
PepperFlashPlayer.plugin: 0x2A052 is not valid resource ID.
Please help us, we use it for production and a lot of users can not record sound
regards, Dmitry
My investigation show:
sometimes the "SampleDataEvent.SAMPLE_DATA" event not triggered (or not assigned) in flash.
To solve this issue I do:
Added to event handler "StatusEvent.STATUS" (or call manually if microphone unmuted):
tti = setInterval(applySampleData, 100);
Added function:
protected function applySampleData() : void {
microphone.removeEventListener(SampleDataEvent.SAMPLE_DATA, recordSampleDataHandler);
microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, recordSampleDataHandler);
}
And in function "recordSampleDataHandler" (it's SampleDataEvent.SAMPLE_DATA listener):
if(tti) { clearInterval(tti); tti = 0; }
Try this.