I have a feature implementation which fully relies on Direct File path access to iterate over files and read files.
Note that the feature only access Shared storage files (not App specific files of other apps).
So according to Google, File API and direct file path access are deprecated in Android 10 and brought back in Android 11.
So, I kept the implementation as is, set targetSdkVersion and compileSdkVersion as 30 (Android 11), set requestLegacyExternalStorage as true and uploaded it to Internal App sharing.
When I tested it on Android 10 and 11, its working with no problems.
My questions -
Is scoped storage implementation not necessary for Android 11?
Will my feature break if I publish to production?
If direct file path access works as is, what is the use of MANAGEMANAGE_EXTERNAL_STORAGE permission? (Ability to access app specific files on External storage?)
As I have to target API 30 by November 1st, wanted to confirm this.
UPDATE: More about what the feature does.
Has a directory path stored in Preferences (Can be changed by user) (Path - /storage/emulated/0/SomeFolder/)
On triggering the function (input is some date time epoch). It will iterate over all the files in the directory (that we have in preferences), checks its last modified time and if it closer to input time, returns the file path. (The files in the directory are created by other app on the phone.)
The file path is then used to upload the file to server.
Related
I want to pick files from storage using flutter, but in all libraries the picked file writes to cache immediately and returns the cached URL (/data/data/package/cache...). Sometimes it's OK, but in case of multiple files and large sized files this is not acceptable. I have tried with image_picker,file_picker etc. Is there anything I am missing or any other libraries that can satisfy my requirement? This is happening while testing in android. I didn't test with iOS.
Use clearTemporaryFiles() method or pick files library below 2.0.0. From version 2.0.0 every file is cached on Android platform.
In Android API 29, we cannot execute a process from the data folder due to W^X violation. Google seems to recommend that we must execute them from the /lib/[arch] folder. However, only files in the format lib[name].so will be installed, even if included in the APK there. Furthermore, when attempting to execute a file that just happens to be be named with that format, it just returns exit code 1 with no exception when doing so. The program does not execute.
This answer indicates something similar, but doesn't mention a "misnamed" file executing:
https://stackoverflow.com/a/62394766/449722
From what I can tell, running native executables included with an APK is now impossible, rather than just calling into shared libraries when targeting API 29. Is this correct, or is there something specific that we need to do.
Google are aware that we need to counterintuitively rename our executables to match the lib….so pattern, but they seem to be comfortable with that, and on several occasions they expressed determination not to break support of running native executables through Runtime.exec(). Actually, it's probably too late to expect them to change the naming convention which has been enacted since Android Cupcake.
This said, there are few extras to take care of:
Make sure that the files are extracted (by default,
android:extractNativeLibs="false" when you build a bundle).
Make sure that the executable does not have unsatisfied dependencies
(e.g. c++_shared).
If your executable needs non-system libraries (on load or through
dlopen()), you must provide the LD_LIBRARY_PATH to your lib
directory (unlike System.loadLibrary(), this is not resolved for
you).
Don't hardcode the path for exec(), use getApplicationInfo().nativeLibraryDir.
I have an application for iOS and Android, but I have never released any updates, that is, it is at version 1. I would like to know if when I release the update (version 2) what will happen with the local files of the app, in the following situations:
An app local file that was not in version 1, was added in version 2
(Ex: an image that was added)
An app local file in version 1, has been removed in version 2 (Ex:
an image that has been removed, will it be deleted or will nothing
happen to it?)
An app local file contained in the version 1 package, has been
changed in version 2 (Ex: an image that has been changed)
An app local file contained in version 1 and 2 (exactly the same
file), was changed by the app in version 1 at runtime, when it is
updated to version 2, will it return to the original? (Ex: a
database that existed in version 1, also exists in version 2, but
since it was changed during use in version 1, will it be replaced by
the database contained in version 2 or will it keep the changes from
version 1?)
An app local file contained in version 1, was changed at runtime by
version 1, but it was also changed in version 2 (Ex: a database that
existed in version 1 was changed at runtime by version 1, but it was
redone in version 2)
#edit
My app was made in Delphi (firemonkey)
An app on iOS is distributed as a bundle (essentially a zip file). The bundle is read-only; it cannot be changed at runtime. When an app is upgraded on iOS the entire bundle is replaced.
An app can copy files from the bundle and save them to the read/write sandbox file system, but you need to write code to do this explicitly.
For your cases:
The additional file will be in the bundle. If you want this file on local storage you need to copy it via code.
The file will no longer be present in the bundle. Any local copy that was made by your previous version will remain.
The updated file will be in the bundle. Any local copy that was made by your previous version will remain and won't be changed.
The app cannot have made changes to files in the bundle, it can only have copied the file from the bundle to local storage before modifying it, so this is essentially case 3.
Again this is basically case 3.
Things may be different on Android.
My app was made in Delphi (firemonkey), I didn't mention it because I thought that replacing local files would be done by the AppStore and PlayStore in the update. But thanks to Paulw11 response, I was able to find out that it was Delphi himself who is responsible for this replacement, and contains a configurable property in each file called "Overwrite".
I need to be able to change out the package name of an existing .apk in order to run simultaneous instances of an Android app I created in Visual Studio using Xamarin. However, I will not reliably have access to the computer with the Xamarin license when I need to change this package name, so I can't simply edit the manifest pre-build. I tried using ApkTool to unpack the apk, edit the manifest, then re-package and re-sign the apk. However, while I am able to install this new apk on a device side-by-side with the original apk, the new app instance fails to start. I receive the following error:
"monodroid" "No assemblies found in '(null)' or '/storage/emulated/0/Android/data/com.newpackagename/files/.override'. Assuming this is part of Fast Deployment. Exiting..."
I assume this means that somehow changing the package name post-build has lost some link to the assemblies. However, I can find no remaining reference to my original package name even after searching the entire unpacked apk (both folders and within files). So I'd like to figure out how to regain these assemblies to allow my app to run. I understand this is very unusual and it may not even be the right way to go about it, but I need the ability to change my package name without having access to Xamarin. This seems like the most promising solution.
Xamarin relies on storing files, unknown to aapt (Android Asset Packaging Tool), within the final built apk. These files are inserted usually in the assemblies folder within the root of the apk with the STORED compression type so that Xamarin can access the files without decompression.
Apktool used to ignore all files that aapt would ignore. IE. If the file isn't a folder/file of this array
private final static String[] APK_STANDARD_ALL_FILENAMES = new String[] {
"classes.dex", "AndroidManifest.xml", "resources.arsc", "res", "lib", "libs", "assets", "META-INF" };
than Apktool would ignore it. However, an attempt was made during development of 2.0.x to include these unknown files.
A bug with the Java 7 NIO library caused all "unknown" files to be stored as DEFLATED. This changed the storage format of the DLLs from STORED to DEFLATED thus this error.
This error was fixed on March 25 - https://github.com/iBotPeaches/Apktool/commit/628286c022e3a872d6ab6bfb3431579f98743c25
As of April 8, 2015 - There are no official releases with this fix in it. You may build Apktool yourself though until 2.0.0 Gold is released.
I need to upload a .apk but it exceeds the 50 MB limit.
I read about this on documentation and some questions but I'm having difficulty making this work.
Does anyone have some tutorials that explain how to do this (using Android Studio) and if there is some way to use Gradle to do this?
I've done this on a few projects, but I never figured out a simple way. The instructions at
http://developer.android.com/google/play/expansion-files.html
helped me get my head around the basics, but I found parts of the process (like "android update project") didn't work properly with Gradle.
The instructions below will help you set up your project with the required libraries. After that you can go back to the official docs and figure out what to do with all the stuff you just included.
Add these permissions to AndroidManifest.xml
<uses-permission android:name="com.android.vending.CHECK_LICENSE"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.WAKE_LOCK"/>
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>
Add Play Services dependency to build.gradle
dependencies {
compile 'com.google.android.gms:play-services:4.0.30'
}
Open SDK Manager and install Google Play APK Expansion Library and Google Play Licensing Library.
Copy java source files from these folders into your project's source/main/java folder:
YOUR-ANDROID-SDK-FOLDER\extras\google\play_apk_expansion\zip_file\src
YOUR-ANDROID-SDK-FOLDER\extras\google\play_apk_expansion\downloader_library\src
YOUR-ANDROID-SDK-FOLDER\extras\google\play_licensing\library\src
Open
YOUR-ANDROID-SDK-FOLDER\extras\google\play_apk_expansion\downloader_library\res
Copy drawable-hdpi, drawable-mdpi and layout into your project's source/main/res folder.
For all files in the values folders, merge content from the file into the matching file in your project.
Create a class which extends android.content.BroadcastReceiver
Add something like this to your manifest:
<receiver android:name="mypackage.MyReceiver"/>
Create a class which extends com.google.android.vending.expansion.downloader.impl.DownloaderService
Add something like this to your manifest:
<service android:name="mypackage.MyDownloaderService"/>
Compile the project and look for errors relating to
import com.android.vending.expansion.downloader.R;
Import your own project resources here instead.
Here is some helfull information for people that end up here in this post since there are some things that changed in the way apk expansions work and also if you are using Android Studio to make the libraries work. So you will need the play services library and the downloader library. (and also the zip tools if you want to use a zip as expansion file and read files and movies directly from the zip without unpacking).
With these libraries it's pretty easy to implement the apk expansion download just make sure:
your activity (the one where you want to implement the downloading
of the expansion pack when the downloading has not been done
automatically) implements IDownloaderClient.
you set up the service & receiver and set them up in your manifest.
The BASE64_PUBLIC_KEY in the service class is correct. Upload the
first apk => look in Services and API's in the developer console
under your app => License code for this app.
This code is used to see if the expansion file can be found on the device:
boolean expansionFilesDelivered() {
for (XAPKFile xf : xAPKS) {
String fileName = Helpers.getExpansionAPKFileName(this, xf.mIsMain, xf.mFileVersion);
Log.i(TAG, "Expansion filename " +fileName);
if (!Helpers.doesFileExist(this, fileName, xf.mFileSize, false))
return false;
}
return true;
}
It uses the class XAPKS wich represents an expansion file, be it either a main or patch file, having a certain filesize(bytes) and associated with a apk version (the one it was first added in).
private static class XAPKFile {
public final boolean mIsMain; // true
public final int mFileVersion; //example 4
public final long mFileSize; //example 126515695L
// example => main expansion that was first introduced in apk version 4 and is 126515695 bytes in size
XAPKFile(boolean isMain, int fileVersion, long fileSize) {
mIsMain = isMain;
mFileVersion = fileVersion;
mFileSize = fileSize;
}
}
Its also quite easy to read movie files and other stuff directly from the expansion file using the zip tools that google has provided (com.android.vending.zipfile).
First get the expansionfile using the methods provided in the library, the paremeters are integers that represent your main expansion apk version (the apk version where the expansion pack you need was first added) and the patch apk version.
ZipResourceFile expansionFile = APKExpansionSupport.getAPKExpansionZipFile(context, APKX_MAIN_APK, APKX_PATCH_APK);
Video
For playing video directly from this zipresourcefile:
AssetFileDescriptor a = expansionFile.getAssetFileDescriptor(pathToFileInsideZip);
Now from this assetFileDescriptor you can get a FileDescriptor and use this in your mediaplayer, the correct syntax to get your mediaplayer to play the video also needs the second and third parameter.. Be it the startoffset and length you can get from the AssetFileDescriptor.
player.setDataSource(a.getFileDescriptor(), a.getStartOffset(), a.getLength());
Other
For all the other stuff (like images) you can just get an inputstream of the zipresourcefile:
expansionFile.getInputStream(pathToFileInsideZip);`
ALSO make sure you don't compress the videos in the zip for this to work!
for example not to compress .mp4 files:
zip -n .mp4 -r zipfile.zip . -x ".*" -x "*/.*"
NOTE 1
You can't use draft anymore as the link to get the expansion file won't be active yet. You have to upload a version to Alpha or Beta first with expansion file. (adding an expansion file is only possible from the second apk you upload and up) So make sure you see the apk expansion file listed when you click the details in the developer publish section under APK.
NOTE 2
If you are using android studio and want to make use of the downloader library don't just copy the package name and java files into your own app src directory. Import the downloader library in eclipse and choose export => gradle build files. Afterwards you can import the library as a module in android studio.
NOTE 3
Not sure of this but I also think it's neccesary to download the app atleast once through the play store and have access to it with the account on your test device. So if you are working with alpha create a google+ test group and add yourself or other test devices to it.
I have just succeeded in making an app that uses the expansion files with Android Studio. Doing this is a monumental challenge. My first advice is that if you just want a big app, make it for an Apple product. Apple accommodates large apps very nicely. On the other hand, Android has made it nearly impossible to make an app larger than 100Meg.
If you do wish to make a big Android app, first get the app working. But do not release any version of the app with a compileSkdVersion larger than 22. Later, I explain that the expansion libraries don't work with a later version so your final app must be version 22 or less. If you do release a later version the Google Store will not let you go back to version 22. In that case, abandon your app identifier and make a new app using version 22.
The libraries and code that you need can be obtained thru tools->android->SDK Manager". On the SDK Tools tab select and load Google Play APK Expansion library and Google Play Licensing Library. At the top of SDK Manager window note the Android SDK Location: field. After the download you can find these files in your SDK directory under extras/google. At this point the directories you are interested in are called market_apk_expansion and market_licensing.
Android documentation on the expansion files give you instructions for linking these libraries into your project. I have spent hours attempting make this work. Generally, Android Studio does bad things. First, it never seems to give error messages when what you enter is not right. Both of the times I got the expansion files to work I incorporated the libraries into my app and did not use the library features of Android Studio. However, putting the libraries into your app is not easy.
First, I should explain that these libraries are old and do not work with the latest SDK versions. I was able to get the libraries to work with a compileSdkVersion of 22. (See build.gradle for the module:app.) The targetSdkVersion should be 22. And under dependencies you should have compile 'com.android.support:appcompat-v7:22.2.1'. This will allow you to use the DisplayWebpageActivity.class. I think this was added in version 23 but it seems to work in this version of 22. I also have added compile 'com.google.android.gms:play-services-appindexing:8.1.0' but I do not know if this is necessary.
In my opinion there is no hope for ordinary people to write the code necessary to download an app. I used the code from the sample that is included in the "extras". You find this sample at /extras/google/market_apk_expansion/downloader_sample. What you need to do is to make this sample app (which does nothing but load the .obb files) be the opening page of your app. Add an Intent to the sample program so that it calls the real first page of your app when the .obb files are present.
The sample program consists of a "res" directory and three .java files. You need to put the three .java files into your main java directory. Change the name of the "res" directory (to "res2") and put this into the same directory that contains your normal "res" directory. To get Android Studio to recognize both "res" directories you add the following to your "build.gradle (Module:app)" file:
sourceSets {
main {
res.srcDirs = ['src/main/res']
res.srcDirs += [ 'src/main/res2']
res.srcDirs += [ 'src/main/res3']
}
}
The above is in the android { } section. The "res3" will come from the libraries.
All of the package names and some of the includes in the three .java sample files must be fixed to match your package name. In "res2" there will be an app name that conflicts with your app name, so delete it. You must fix your manifest so that it starts to execute SampleDownloaderActivity. And fix SampleDownloaderActivity so that it call the start of your app when the .obb files are there.
The Android documentation suggests that you make your .obb file a zip archive. I did this with my first expansion file app. For my application this did not work well. I had lots of small images. These images were already compressed (.jpg). Accessing any image was slow so I ended up making a poorly performing app.
In the second expansion app I used the "patch" file for a directory and put the photos into the "main" file. To access a photo the patch file is read and put into a dictionary that contains photo names, locations and lengths. This lets the app find where an image is in the main file, which is treated as a random access file. The photos that I need are copied into the storage for the app and given their proper names (xxx.jpg). The photos are then accessed inside of HTML code.
The two libraries are also integrated into the app. There is a "res" directory that is renamed to "res3" and put into the same directory as the regular "res" directory. In my app/src/main/java/com/developer/app_name directory I added a "downloader" and "licensing" directories. I wrote a program to move the libraries into their directories while fixing the package names and other occurrences of the original package name. The program only got some of the names that needed to be changed. Keep working on getting all these names fixed while ignoring some other kinds of errors. Many things that reference the "res3" directory did not work until I added an import statement like this:
import com.developer.app_name.R;
In the licensing library the LicenseChecker.java file contains code that will crash in SDK version 22. You must fix this code or use an older SDK version. Go to around line 150. Comment out the code that starts with boolean bindResult = mContext to Context.BIND_AUTO_CREATE);. Replace it with the following:
Intent serviceIntent = new Intent(
new String(Base64.decode("Y29tLmFuZHJvaWQudmVuZGluZy5saWNlbnNpbmcuSUxpY2Vuc2luZ1NlcnZpY2U=")));
serviceIntent.setPackage("com.android.vending");
There are a couple other errors in the library where Android Studio gives good suggestions on ways to fix them.
During debug you can manually put the .obb files into your device. On my Android this is done in Nexus 5/Internal storage/Android/obb where I make a folder called com.developer.app_name. I have discovered that what I see on my computer is not always what is in the device. Sometimes I must power the device off and on in order to see what is actually there. I spent lots of time trying to understand why the app could not find the .obb files when I could see them thru the computer. In fact, the .obb files were not there.
After you app works in debug with and without the .obb files, and without the .obb files it tells you that they can't be obtained from the store, it is time to take the app to production in order to finish testing it. If this is the first upload to the store the upload software fails to ask for the .obb files. So upload your app. Then, before attempting to release it, change the load number and version number and upload it a second time. This time it will ask for the .obb files.
Add them as a modules , Or import them in eclipse as a libraries ,go to Android studio and import non android studio project .. Go to Project Directory