Based on the IndexedDB of Cordova Storage documentation, the storage is limited to around 5MB (the last point of the Disadvantages paragraph).
I need far more storage for my app, thus I have to break the jail without any other option.
Round 1: Ask for more storage quota.
navigator.webkitPersistentStorage.requestQuota(quota, function(granted) {
window.requestFileSystem(window.PERSISTENT, granted, cbSucc, cbErr);
}, cbErr);
The 'granted' alway zero no matter what 'quota' is.
There is no requestFileSystem() function in the 'window' object on Android webview.
Based on (https://stackoverflow.com/a/42355894) : it only works for the sandboxed filesystem. Maybe this is not what I need anyway.
Round 2: Implement a Push Notification service worker which will grant persistence storage permission automatically.
navigator.serviceWorker.register('sw.js')
.then(function(swNotify) {
swNotify.pushManager.subscribe({
userVisibleOnly : true,
applicationServerKey : pubKey
});
});
The service worker is registered.
There is no PushManager on Android webview, thus no way to do pushManager.subscribe().
This works fine for Chrome on desktop and Android except webview.
Round 3: Ask for durable storage permission.
navigator.storage.persist().then(...);
The persist() function always returns false without asking user to grant permission.
The WRITE_EXTERNAL_STORAGE permission is already requested and granted.
Environment :
Android: 7.0 (by Android Emulator)
WebView: 58.0.3029.83
Cordova: 7.0.1
andorid platform of Cordova: 6.2.3
I am still a prisoner of the 5MB jail, what can I do else?
You could use the cordova-sqlite-storage plugin to create a native SQLite database with unlimited storage:
Unlike IndexedDB (and WebSQL) which are integrated into the Webview, this uses a native database which is stored in a .db file on disk.
Currently there is no IndexedDB interface shim (although it's on the TODO list) so you'd need to rework the API calls to the database. However there is, for example, an adapter for Lawnchair which makes for an easy-to-use API.
Related
Since Android Q came out there are some privacy changes in the permissions about read from external storage. I have a chat application that the user can choose a photo from Downloads etc... and send it. So i need to have access to that files. The way i did this is by using contentProvider.
context.contentResolver.openInputStream(uri)?.use { inputStream ->
while (true) {
numBytesRead = inputStream.read(buffer)
// .. do stuff
}
}
The uri that is available at that time is -> file:///storage/emulated/0/Download/myFile.pdf
However i get a FileNotFoundException but the file trully exists.
I have set all the permissions in the manifest and granted them on the launch of the app. From Android <= 9 it works properly.
So what do i have to do...?
I have a chat application that the user can choose a photo from Downloads etc... and send it
That will not be possible on Android 10 and higher. You need to switch to something else. For example, you could use ACTION_OPEN_DOCUMENT to allow the user to choose content from anywhere the user wants. Then, use the resulting Uri to upload it to your chat server, akin to how you are using the Uri in your code snippet. Or, better yet, don't read it all into memory — use something like this OkHttp InputStreamRequestBody implementation.
For Android 10, you can add android:requestLegacyExternalStorage="true" to your <application> element in the manifest. This opts you into the legacy storage model, and your existing external storage code will work. That will not work on Android R and higher, though, so this is only a short-term fix.
I have a system application with all the necessary permissions. previously, i would download apks using the DownloadManager and then use reflection via PackageManager's installPackage() to install said apk.
unfortunately, following N's behaviour changes
http://developer.android.com/preview/behavior-changes.html :
The DownloadManager can no longer share privately stored files by filename. Legacy applications may end up with an unaccessible path when accessing COLUMN_LOCAL_FILENAME. Apps targeting Android N or higher trigger a SecurityException when attempting to access COLUMN_LOCAL_FILENAME. Legacy applications that set the download location to a public location by using setDestinationInExternalFilesDir(Context, String, String) or setDestinationInExternalPublicDir(String, String) can still access the path in COLUMN_LOCAL_FILENAME, however, this method is strongly discouraged. The preferred way of accessing a file exposed by the DownloadManager is using openFileDescriptor(Uri, String).
I am now getting a permission denied error when trying it the old way.
I need a Uri to pass to PM's installPackage(), and so i currently just copy the file to my application's private folder with a (depcrecated) WORLD_READABLE mode, so that the PM can later access it and install. This feels very hacky and i was wondering if anyone knows of a better way (The other option suggested by androiddev is to download the file to a public dir, but this would require me to add the WRITE_EXTERNAL_STORAGE permissions which is not an option.)
I'm using reflection method freeStorageAndNotify:
Method freeStorageAndNotify = null;
freeStorageAndNotify = service.packageManager.getClass().getMethod(
"freeStorageAndNotify", long.class, IPackageDataObserver.class);
freeStorageAndNotify.invoke(PackageManager.class, maxCache + freeSpace, packageDataObserver);
This causes InvocationTargetException:
java.lang.SecurityException: Neither user 10199 nor current process has android.permission.CLEAR_APP_CACHE.
Some points:
- I already have android.permission.CLEAR_APP_CACHE
- This happens only in android "M" Version (Flashed the preview sdk from developer site)
I know this is a hack, and google doesn't bring some official API for that,
But there are so many cleaning apps which cleans all the device cache in one click, so if someone know how to bypass this issue with another workaround i'll be happy to see that.
Thanks very much for the help
There was a bug raised on Android 5 regarding how any app can wipe out all cache files with a regular permission, but cannot wipe out one package's cache files except with a signature-level permission. It's details where
PackageManager has a deleteApplicationCacheFiles() to delete the cache from one package.
This method is hidden from the SDK, and it requires
DELETE_CACHE_FILES, a signature-level permission.
PackageManager also has a freeStorageAndNotify() method, to delete
cache files from all packages. This method is hidden from the SDK, and
it requires the CLEAR_APP_CACHE permission, which is merely flagged
as "dangerous".
It was proposed to either that DELETE_CACHE_FILES should have its level relaxed,
CLEAR_APP_CACHE should have its level raised.
A framework engineer responded
Note that freeStorageAndNotify's purpose is not to wipe out all cache
files, but to free up X amount of space, for example by play store
before it tries to download and install an app. So there are reasons
to use it that work well with the system, but no reason for an app to
use the method that just blindly erases all cache files for a single
app (that is just there for the Settings app UI).
If indeed it is not an app error i.e. you haven't messed up the permissions and it works on Marshmallow / 6 / api 23 and not others that could only mean it became a signature level permission as well, like DELETE_CACHE_FILES.
A signature|system permission, meaning that it can only be held by
apps that are signed with the firmware's signing key or are installed
on the system partition (e.g., by a rooted device user). As described
in this answer.
This would make sense, considering their intended use / their vision (no reason for an app to use the method that just blindly erases all cache files for a single app). It may have even been restricted as a result of that bug. When Android 6's code will come out we will know better (current available is 5.1.1 - link to PackageManager's freeStorageAndNotify).
Refer to these pages: permissions by protection level and protection level definitions.
android.permission.CLEAR_APP_CACHE
This falls under the protection level "signature|privileged" which means that only same-signature or privileged apps (system signed basically) can have this permission.
Also you should check out the Behavior Changes in general.
I am developing a Sencha-Touch + PhoneGap application for Android and I am facing an issue that the web-view gets reloaded if the app was minimized for a long time.
The same thing happened when we run any memory cleaner apps on the device(Like Android Assistant,Clean Master etc..)
There is a login functionality in my app.So if the memory is cleared, the user needs to re-login to the app and the data inside the app will also be lost.(Please note that the data is very important)
How to prevent reload on android web-view when the app comes to foreground?
Or please suggest an alternative solution for retaining the user data.
Please note that I am using cordova 2.3 and sencha touch 2.3
Thanks in advance.
I think you need a client side data storage solution. Sencha Touch offer two solutions that may help you with this issue.
localstorage - http://docs.sencha.com/touch/2.3.1/#!/api/Ext.data.proxy.LocalStorage
Specify a proxy on your store to use local storage
proxy: {
type: 'localstorage',
id : 'important-data'
}
sql storage - http://docs.sencha.com/touch/2.3.1/#!/api/Ext.data.proxy.Sql
Specify a proxy on your store.
proxy: {
type: "sql"
}
With either of the above solutions your data will be available client side independent of the webview being reloaded.
I have currently built an application using phone gap targeting the android and blackberry platforms.
I use a combination of Jquery mobile and Phonegap for my application, since both are open source frameworks and improvements as well as bug fixes keep happening I wanted to know what would be a good solution for alerting my users to update their application when I upgrade the above frameworks in my application.
One solution I had in mind is maintain a version numbering on my server for the apps, when the app is loaded on the users device we can make an ajax call to check for version update and then alert the user to upgrade their application.
Android market also has an auto update feature how does that work! How do I go about this what would be a good approach.
If you are planning to build "native", in this case localy installed apps. You don't have to worry about informing the user. As soon as you uplad the new versions to the Android market or App World the App market systems will let the users know automatically.
I think (in most cases) it is not necessary to let the user know about updates within the app. Some apps do that but I see it less often since it really does not make much sense.
But in case you want to build such a feature, I would store a version number somwhere in the code and make a server request eg. when the app starts which then compares the latest version number of your app stored on your server.
Eg.
Client:
$.ajax({
url: webservice_host + '&callback=?',
dataType: 'jsonp',
success: function (data) {
//data -> remote version
var local_version;
if (local_version < data ){
alert("There is a newer version available");
}
}
});
Server (php in this case):
<?php
print mysql_real_escape_string($_GET['callback']). '( 1.1 )';
?>
I didn't test the code for typos etc. But this should do the trick.