I have a product using Android 2.3, and my app is put into /system/app/.
Now when my app find new version, my app try to download the .apk(updated version) file to /system/app/ , but failed. I couldn't create file in /system/app/.
So, how could I update my app locate in /system/app?
(I have all source code of Android+Linux kernel+uboot of my product.)
piece of code:
case WdtMessage.UPDATE:
Log.i(TAG, "======================update");
FileOutputStream out = null;
try {
out = new FileOutputStream("/system/app/dddddddd.apk");
out.write((updateFileBuffer));
}catch (Exception e) {
// TODO: handle exception
Log.i(TAG, "======================err"+e.toString());
}
create file Permission denied!
Google's new policy doesn't allow apps in the Play Store that try to update themselves. Updates must be passed through the Play Store.
If you're not looking to put your app up in the store, as far as I know, you wont be able to overwrite the APK (without root access).
PS : Facebook recently did something similar with their application, if you really need this, try researching how they did it.
EDIT:
For your requirements, you will need root access. So the device you're developing on needs to be rooted. With that in mind , you could use RootTools to access the /system/app/ directory.
Related
I'm going to develop an android app for a museum, which will handle a tablet with the app installed on it to the visitors.
The app will be on foreground full time and visitor will only be able to use this app.
Since there will be many tablets, and they are all under our control, I would like a way to update all the tablets remotly with the last version of the app.
Is there a way to achive this?
Is there a way to achive this?
Answer is : Yes but with one exception lets have a look.
Step 1 : Create a local server for your museum. I guess it is already in the museum.
Step 2 : Now In your android application whenever you start your app check that whether new version of APK is available. For checking APK new version you can use this code.
PackageInfo packageInfo = getPackageManager().getPackageInfo(context.getPackageName(), 0);
int apkVersion = packageInfo.versionCode;
You should set your APK name like "yourAppname_version" so whenever you upload the new app to your local server just change the name so you can easily identify that new version of APK is available or not.
Step 3 : If new version is available then start downloading APK from the local server and save it to your storage directory.
Step 4 : When downloading completed you can call this set of code to install the new APK.
Intent intentApkInstall = new Intent(Intent.ACTION_VIEW);
intentApkInstall.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory()+"/"+"yourAppname_version.apk")), "application/vnd.android.package-archive");
intentApkInstall.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intentApkInstall);
Now the Exception part is here the above code will prompt user to install APK. So in this case you have to install it manually.
Working with Lollipop, I have a device-owner app that is installed with NFC at provision time.
What I need now is to handle automatic updates for my App, from Google Play to rely on the standard Android App update system...
So far I can imagine 2 ways to get this done, but don't know how to handle any of them :
in my NFC install constant EXTRA PROVISIONING DEVICE ADMIN PACKAGE
DOWNLOAD LOCATION install the App directly from the Play Store instead of the url on my own dev server. However
this constant need to handle the url of an apk file, and I did not find any
official way to get apk install direct from Play Store ? (as it will
be a production App in the future I'm not interested in hacks)
keep installing the apk from the dev server, but then allow the App
to update itself with its little brother located on the Play Store
with the same package name. To say it an other way: Would this be possible to install a v1 apk from a custom location, then put a v2 on the PlayStore... and let the magic come true ?
I'd be glad to hear if anyone could share experience about such procedures. Thanks for reading!
EDIT after #Stephan Branczyk suggestion I could make some more testing, here is what I did and the results:
1 - In the NFC provisioning I replaced the apk url with
snep://my.app.packagename without luck ; it just gives an error
without much explanation.
2 - I replaced this url by such a PlayStore link :
https://play.google.com/store/apps/details?id=my.app.packagename but
it gives a checksum error whether I use the checksum locally
computed, or the checksum given on the GooglePlay apk details. It looks not so far from the goal but I could not make it work.
3 - Finally I came back on my first solution, a self-hosted apk
versioned 1... but this time I tried to put on the PlayStore a newer
version 2 of the app with the exact same packagename... That led me
to strange things:
At first my App did not appear anywhere in the local PlayStore App,
but when I searched for it in Google Play, it showed up with the green
"installed" badge, and it proposed me to make an update... So did I.
Then, after this first manual update, the App is in v2, nice, and
better: it appears well listed in my PlayStore.
Optimistically, I uploaded a v3 of the App... just to see if my
PlayStore would automatically update my app (as is does for all the
other ones), but sadly no luck : even if my app is still listed in the
playstore, and proposing the "update" button... it never
updates by itself as it should ; I still need to click on it manually.
Isn't it a strange behavior ? If some have ideas about it, I would really need to be able to rely on the Play Store functionalities but so far no luck, and I cannot believe that Device-Owner app distribution is not compatible with PlayStore ?
Just in case, FYI here is the kind of provisioning code I'm using:
try {
Properties p = new Properties();
p.setProperty(
DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME,
"my.app.packagename");
p.setProperty(
DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_DOWNLOAD_LOCATION,
"http://www.example.com/myDeviceOwnerApp.apk");
p.setProperty(
DevicePolicyManager.EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM,
"U55o3fO0cXQtUoQCbQEO9c_gKrs");
ByteArrayOutputStream bos = new ByteArrayOutputStream();
OutputStream out = new ObjectOutputStream(bos);
p.store(out, "");
final byte[] bytes = bos.toByteArray();
NdefMessage msg = new NdefMessage(NdefRecord.createMime(
DevicePolicyManager.MIME_TYPE_PROVISIONING_NFC, bytes));
return msg;
} catch (Exception e) {
throw new RuntimeException(e);
}
Write your package name as an AAR record in the tag.
To confirm that this functionality works, use this app to write the tag with.
You need to set Base64 encoded SHA1 or SHA256 (from M forward) of the apk in the
EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM
field when provisioning through NFC otherwise the provisioned device will not accept the URL for download.
Also see this answer for properly encoding the checksum.
I'm trying to find a solution to do a remote update of an APK to 80 tablets. This should preferably be as automated as possible and if this can happen completely in the background without any user input that would be great. Basically what the Playstore currently do which I unfortunately can't use.
Is something like this possible without rooting the device? Any suggestion on libraries/ services that does this?
I'm running Android 4.1.1 and they will all be connected to a Wi-Fi.
You can download the new APK file to SD card, then call this to install it:
Intent shareIntent = new Intent(Intent.ACTION_VIEW);
shareIntent.setDataAndType(Uri.fromFile(new File("path-to-APK-file")),
"application/vnd.android.package-archive");
try {
context.startActivity(shareIntent);
} catch (Throwable t) {
// handle the exception here
}
There is only one thing not automatic: the final step. The system will ask the user to confirm installation.
About the MIME type of APK files, here's the wiki page.
No, in the background isn't possible without rooting or having the device's signing key at least as a standard Android APK update. The only semi-reasonable way I can envision something similar to this working is for your app to always check for/download code to run which you load using a class loader. This would be a significant amount of work and not easy.
However, if you're willing to live with some user interaction, it really shouldn't be that hard (though it'll still take some building of infrastructure). Keep a web service that returns the latest version number, compare with the current version number and download the new APK as necessary. Installing an APK programmatically has been covered in many SO questions.
As stated in my question above, is it possible to have an apk file within another apk?
To further explain, here is my situation:
I have two apps and the first one calls the other through an intent.. I don't have problem with this.. But what I need is to install only one apk file instead of two. And the first thing that came into my mind is to put a .apk file inside the other .apk file.. I really don't know if this is possible that's why I need your take on this. But if this is not possible, I hope someone can tell me what would be the best practice to doing this kind of thing.
I can make it as one application, but that would be my last solution.
I just did that right now ...
I put apk 2 in raw/embeddedapk.apk
then this code ... started the installer for apk 2 ... **problem if user phone doesnt allow application not from market .. it will fail to install apk 2 ...
remember to delete temp file when the instalation is finished ....
try {
InputStream in = this.getResources().openRawResource(R.raw.embeddedapk);
byte[] b = new byte[in.available()];
int read = in.read(b);
toast(read + " byte read");
String tempFileName = "embeddedapk.apk";
FileOutputStream fout = openFileOutput(tempFileName, MODE_WORLD_READABLE);
fout.write(b);
fout.close();
in.close();
File tempFile = getFileStreamPath(tempFileName);
Intent i = getFileActionIntent(Intent.ACTION_VIEW, tempFile);
startActivity(Intent.createChooser(i, "sdsds"));
}
catch (Exception ex){
Log.e("ero", "erer", ex);
}
My reason is I want to have apk 1 userinterface and apk 2 data provider as seperate apps in market. but i don't wnat users to down then individually when installing first time ...
apk 1 need data from apk 2, apk 2 does not have any activities ..
When user downloads apk 1 from market I want to auto instal apk 2 ...
I want to be able to update (market) apk1 & apk 2 independantly ...
Perhaps an Android Library is what you are looking for. This is a place where you can put some common code and include it in multiple applications (apks).
See this documentation on library projects.
Sorry, you are out of luck if you want APK inside APK.
Android does not allow you to do so.
But I am curious about why you would want it that way ?? You can call one activity from the other even if they are in the same APK.
You can program it as one application and having two launcher so that it appears to the user as being two stand alone applications.
You could also try to fire the intent and catch the case that no one is reacting on it. Than you can open the market and recommend to install the application, too.
The last way is mostly done by applications that need file browsers to pick files. They send an intent and if there is no file browser installed, they prompting a toast informing that a file browser is needed to perform the task and they open the market page of astro, OI file manager or another app they prefer...
I'm developing a non-public Android app, i.e. the app won't be available in the global Android Market. The app will be installed on a limited number of clients, e.g. by using an apk file.
How can I enable an auto-update functionality in this app?
I see different potential options (I do not know if those are technically hard or even impossible to implement or if there are any existing functionalities that can be reused):
On each launch the app tests if a new version exists (by requesting a server), if so downloads the new apk and replaces itself with the new version.
Use (or develop?) a separated app or service that undertakes the update-check and replacement-process.
Use (or develop?) a private market app which has an auto-update option. This option is similar to the second one, but more generic: The market app would be connected to a repository, i.e. it would handle an arbitrary number of (private) apps.
I would prefer option one since the auto-update functionality is included in the app which needs less development efforts.
janjonas, in the company I work we had a similar problem with Windows Mobile 6.x, and we use pretty much the same solution pointed by EboMike:
The main app check if it's updated, against a WebService. It receives the current version & the URL from where download the new version, if necessary. The main app then start the Updater app, passing the URL, and quit.
The Updater do the download of the new program, via HTTP, showing to the user the % downloaded. The user can cancel the download anytime, in a controlled way, and the Updater can registry this cancellation.
Since the new app is downloaded, the Updater run the new app, and quit.
I think option one is the least amount of work for you, and actually the cleanest one too since it will go through the proper channel of using Android's built-in package installer which includes user notification and the option for the user to abort the installation if desired.
You already have it all outlined - check for a new version on a server (would be nice to give the user the option to turn that off), and if there is a new version, you could either just link to the URL with the APK (which will, IIRC, use the browser's download manager to download it), or you could download it with your app and then point the intent to your local file. Using the HTTP link is technically less work and cleaner - the more you let the operating system do, the better - unless there's a reason not to.
Enabling "Install non-market app" is still needed for any application outside the Google Play. If it not enabled, the installation process is going to ask for it and redirect the user to the Application Settings, and after that, the user can install the app.
Depending on your needs, you can delegate to a third part lib.
Some of the permissions we'll use to get this done are the following:
<uses-permission android:name="android.permission.ACCESS_SUPERUSER" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Let me explain a bit... The last, WRITE_EXTERNAL_STORAGE, is self-explanatory. With ACCESS_SUPERUSER we'll tell the system that we intend to use root privileges. READ_EXTERNAL_STORAGE will be needed in the future in order for your app to read files on SD card.
Assuming that you have downloaded the file and that all those devices can be rooted (limited number of clients, not on Play, etc.), you could do this:
String filePath = Environment.getExternalStorageDirectory().toString() + "/your_app_directory/your_app_filename.apk";
Process installProcess = null;
int installResult = -1337;
try {
installProcess = Runtime.getRuntime().exec("su -c pm install -r " + filePath);
} catch (IOException e) {
// Handle IOException the way you like.
}
if (installProcess != null) {
try {
installResult = installProcess.waitFor();
} catch(InterruptedException e) {
// Handle InterruptedException the way you like.
}
if (installResult == 0) {
// Success!
} else {
// Failure. :-/
}
} else {
// Failure 2. :-(
}
Here might be a very lame method but for some companies, if you believe its applicable, this might be very easy to implement.
Create an password screen (passwordActivity) that asks a password to access the application.
Once the password is entered, raise a flag (set a boolean value from false to true using sharedpreferences)
Place the .apk file on Google Store.
Change the password once everyone installs the app, and release a new update on Google Play Store.
Since the software is going to cache the flag value, the password screen won`t show up even the password is change. It will only show up for new installations so might need to repeat the process.
Note: This method might better fit if there is not hundreds of users using the application. And don`t forget this method is also not secure. To sum up, if you are looking a way to keep the application private and have no security concerns, this is what I recommend.
Update app
Make sure that you already have your new apk download on location
void installNewVersion(String location) {
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(location + "app-debug.apk")),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}