Parse error when programmatically installing an APK - android

I am trying to create a mechanism for an app to update itself by downloading and installing a later APK from within the app.
I have an APK located on a server which installs fine if I simply navigate to the URI then open the .apk file. The problem comes when I try to install it programmatically. I get "Parse Error - There was a problem while parsing the package"
The target phone allows install from unknown sources and within AndroidManifest.xml I request these permissions:
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.REQUEST_WRITE_PERMISSION"/>
The code to perform the update has been taken from another thread here on StackOverflow and changed slightly to suit my particular situation.
public class UpdateApp extends AsyncTask<String,Void,Void> {
private Context context;
public void setContext(Context contextf){
context = contextf;
}
#Override
protected Void doInBackground(String... arg0) {
try {
URL url = new URL(arg0[0]);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.setDoOutput(true);
conn.connect();
File file = context.getCacheDir();
file.mkdirs();
File outputFile = new File(file, "update.apk");
if(outputFile.exists()){
outputFile.delete();
}
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = conn.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(outputFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (Throwable ex) {
Toast.makeText(context, ex.toString(), Toast.LENGTH_LONG).show();
}
return null;
}
}
What can I try in order to understand why the APK is generating an error when installed from within the code but installs without issue when downloaded from the server?
The app is being built for API 23 although it will be required to work with API 24 once complete.

You will have to make your cached apk file world-readable.
After is.close();
put
outputFile.setReadable(true, false);

This works for me on Android 8
startActivity(Intent(Intent.ACTION_VIEW).apply {
type = "application/vnd.android.package-archive"
data = FileProvider.getUriForFile(applicationContext, "$packageName.fileprovider", file)
addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
})

Related

Download/Install apk Version 23>

After reading multiple post concerning this subject I have been able to put together the info needed to download an update for my apk and have it install. This is successful for versions under 23. After reading more post I discovered for versions 23> there is a slight difference in the way to execute the install. I have put together this info in the following code but I am still encountering a problem with the version 23>. I pretty much understand what the code is doing, but I have no idea why it fails to run.
try {
URL url = new URL(arg0[0]);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
String PATH= Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath() +"/";
File file = new File(PATH);
file.mkdirs();
File outputFile = new File(file, "maga.apk");
if(outputFile.exists()){
Log.i("SCROLLS ", "file exist-delete");
outputFile.delete();
}
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
if(outputFile.exists()){
Log.i("SCROLLS ", "file exist");
}
if (Build.VERSION.SDK_INT >= 23) {
File toInstall=new File(Uri.parse(PATH+"maga.apk").getPath());
Log.i("SCROLLS ", "toInstall "+ toInstall);
Uri apkUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".provider", toInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
} else {
File toInstall = new File(PATH, "maga" + ".apk");
Uri apkUri = Uri.fromFile(toInstall);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
} catch (Exception e) {
Log.e("SCROLLS ", "Update error! " + e.getMessage());
}
return null;
}
}
When executed on an emulator with Version <23 all works. On an emulator over 23, the progress gets into the If statement and sets the toInstall value but nothing happens after that. The only thing I see in Logcat resembling and error that pertains to this is
03-24 01:35:16.562 5300-5300/com.google.android.packageinstaller E/InstallStart: Requesting uid 10079 needs to declare permission android.permission.REQUEST_INSTALL_PACKAGES
Looking into this it's my understanding that this permission is for system apps so adding it to Manifest does no good. Is there something missing from my code or a permission? I have added the provider to the manifest and the provider_paths.xml file to the project. Thanks for any help.

How to download a file in Android

What i have:
I have uploaded a .json file to the Dropbox of my account I have
made it public
What i am trying to do:
I want to download the file to my RAW folder of my android project
I am familiar with AsyncTask and HttpClient but what
methodology(steps) should I follow to download the file?
I tried searching for a similar question in stackoverflow but couldn't find one so posting a question myself
You cannot download a file into "assets" or "/res/raw". Those get compiled into your APK.
You can download the file to your apps internal data directories. See Saving Files | Android Developers.
There are plenty of examples and libraries to help you with the download. The following is a static factory method you could use in your project:
public static void download(String url, File file) throws MalformedURLException, IOException {
URLConnection ucon = new URL(url).openConnection();
HttpURLConnection httpConnection = (HttpURLConnection) ucon;
int responseCode = httpConnection.getResponseCode();
if (responseCode == HttpURLConnection.HTTP_OK) {
BufferedInputStream bis = new BufferedInputStream(ucon.getInputStream());
ByteArrayBuffer baf = new ByteArrayBuffer(50);
int current = 0;
while ((current = bis.read()) != -1) {
baf.append((byte) current);
}
FileOutputStream fos = new FileOutputStream(file);
fos.write(baf.toByteArray());
fos.close();
bis.close();
}
}
Then, to download a file from Dropbox:
String url = "https://dl.dropboxusercontent.com/u/27262221/test.txt";
File file = new File(getFilesDir(), "test.txt");
try {
download(url, file);
} catch (MalformedURLException e) {
// TODO handle error
} catch (IOException e) {
// TODO handle error
}
Please note that the above code should be run from a background thread or you will get a NetworkOnMainThreadException.
You will also need to declare the following permission in your AndroidManifest:
<uses-permission android:name="android.permission.INTERNET" />
You can find some helpful libraries here: https://android-arsenal.com/free
I personally recommend http-request. You could download your dropbox file with HttpRequest like this:
HttpRequest.get("https://dl.dropboxusercontent.com/u/27262221/test.txt").receive(
new File(getFilesDir(), "test.txt"));

Android: How do I download a file from a dynamic url webview

In my app I am using a webview to navigate through to a site, automatically fill in a web form using javascript then submit to obtain a link to a CSV export file.
The link looks like this: XYZ.com/TEST/index/getexport?id=130.
I'd like to download the file this URL points to, then when complete read it into a local database but I'm having trouble downloading the linked file.
If I simply try to open the URL in webview I get an error from the webpage telling me no such file exists.
If I use the Download Manager to download it myself, the source code is downloaded as an html file, not the associated .csv file.
I can open the url with an ACTION_VIEW intent and a browser (chrome) downloads the correct file, but this way I have no notification of when the download completes.
Any ideas of how to download my .CSV file?
To download a file from webview use this :
mWebView.setDownloadListener(new DownloadListener(){
public void onDownloadStart(String url, String userAgent, String contentDisposition, String mimetype, long contentLength){
Intent i = new Intent(Intent.ACTION_VIEW);
i.setData(Uri.parse(url));
startActivity(i);
}
});
Hope this helps.
You could resort to manually downloading the file from the url using an AsyncTask.
Here id the background part:
#Override
protected String doInBackground(Void... params) {
String filename = "inputAFileName";
HttpURLConnection c;
try {
URL url = new URL("http://someurl/" + filename);
c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
} catch (IOException e1) {
return e1.getMessage();
}
File myFilesDir = new File(Environment
.getExternalStorageDirectory().getAbsolutePath()
+ "/Download");
File file = new File(myFilesDir, filename);
if (file.exists()) {
file.delete();
}
if ((myFilesDir.mkdirs() || myFilesDir.isDirectory())) {
try {
InputStream is = c.getInputStream();
FileOutputStream fos = new FileOutputStream(myFilesDir
+ "/" + filename);
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
} catch (Exception e) {
return e.getMessage();
}
if (file.exists()) {
return "File downloaded!";
} else {
Log.e(TAG, "file not found");
}
} else {
Log.e(TAG, "unable to create folder");
}
}
Perhaps it would make sense to refactor it so that the file is returned. Then you get the file as an argument in onPostExecute as soon as the download is complete.

downloading terminates when App goes to background

I am working on an App, that uses phonegap.
When the App is started for the first time, I am downloading the data from the server.
That downloading process is being executed in AsyncTask, and in onPostExecute() of that, I am loading the url.
The problem being arose is that, when my download process is getting executed, and the App somehow goes to the background, the downloading gets terminated, unfortunately, which is absolutely not required.
To overcome this trouble; I guess, using service is one of the good options. But, in that case, another question arises, that is, how can I possibly, load the url inside service.
Otherwise, what else can be done?
Please, suggest me the possible ways to get rid off this trouble, I am currently facing.
Use the similar method for downloading the data. This may be helpful.
public void downloadUsingGET(String apkurl, String fileName) {
try {
String PATH = Environment.getExternalStorageDirectory()+"/Android/data/"+getPackageName()+"/files/";
URL url = new URL(apkurl);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.connect();
File file = new File(PATH);
file.mkdirs();
File outputFile = new File(file, fileName);
FileOutputStream fos = new FileOutputStream(outputFile);
InputStream is = c.getInputStream();
byte[] buffer = new byte[1024];
int len1 = 0;
while ((len1 = is.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
is.close();
} catch (IOException e) {
}
}
If you use a service, you can pass strings trough an intent(the intent you started the service).

How to read PDF file saved to internal storage of device?

I am using following code to download and read a PDF file from internal storage on device.
I am able to download the files successfully to the directory:
data/data/packagename/app_books/file.pdf
But I am unable to read the file using a PDF reader application like Adobe Reader.
Code to download file
//Creating an internal dir;
File mydir = getApplicationContext().getDir("books", Context.MODE_WORLD_READABLE);
try {
File file = new File(mydir, outputFileName);
URL downloadUrl = new URL(url);
URLConnection ucon = downloadUrl.openConnection();
ucon.connect();
InputStream is = ucon.getInputStream();
FileOutputStream fos = new FileOutputStream(file);
byte data[] = new byte[1024];
int current = 0;
while ((current = is.read(data)) != -1) {
fos.write(data, 0, current);
}
is.close();
fos.flush();
fos.close();
isFileDownloaded=true;
} catch (IOException e) {
e.printStackTrace();
isFileDownloaded = false;
System.out.println(outputFileName + " not downloaded");
}
if (isFileDownloaded)
System.out.println(outputFileName + " downloaded");
return isFileDownloaded;
Code to read the file
PackageManager packageManager = getPackageManager();
Intent testIntent = new Intent(Intent.ACTION_VIEW);
testIntent.setType("application/pdf");
List list = packageManager.queryIntentActivities(testIntent,
PackageManager.MATCH_DEFAULT_ONLY);
try {
Intent intent = new Intent();
intent.setAction(Intent.ACTION_VIEW);
File fileToRead = new File(
"/data/data/com.example.filedownloader/app_books/Book.pdf");
Uri uri = Uri.fromFile(fileToRead.getAbsoluteFile());
intent.setDataAndType(uri, "application/pdf");
startActivity(intent);
} catch (Exception ex) {
Log.i(getClass().toString(), ex.toString());
Toast.makeText(MainActivity.this,
"Cannot open your selected file, try again later",
Toast.LENGTH_SHORT).show();
}
All works fine but the reader app says "File Path is not valid".
Your path is only valid for your app. Place the file in a place where other apps can 'see' it. Use GetExternalFilesDir() or getExternalStorageDirectory().
Note about files which are created inside the directory created by Context.getDir(String name, int mode) that they will only be accessible by your own application; you can only set the mode of the entire directory, not of individual files.
So you can use Context.openFileOutput(String name, int mode). I'm re-using your code for an example:
try {
// Now we use Context.MODE_WORLD_READABLE for this file
FileOutputStream fos = openFileOutput(outputFileName,
Context.MODE_WORLD_READABLE);
// Download data and store it to `fos`
// ...
You might want to take a look at this guide: Using the Internal Storage.
If you would like to keep the file app specific, you can use PdfRenderer available for Lollipop and above builds. There are great tutorials on google and youtube that work well. The method you are using is a secure way to store a PDF file that is only readable from inside the app ONLY. No outside application like Adobe PDF Reader will be able to even see the file.It took me a lot of seaching but I found a solution to my specific usage by using this site and especially youtube.
How to download PDF file from asset folder to storage by making folder
make sure you have storage permission are given like marshmallow device support etc then follow these steps
private void CopyReadAssets()
{
AssetManager assetManager = getContext().getAssets();
FileInputStream in = null;
FileOutputStream out = null;
File sdcard = Environment.getExternalStorageDirectory();
File dir = new File(Environment.getExternalStorageDirectory()+File.separator+ "A_level");
File dir2;
if (dir.exists() && dir.isDirectory()){
Log.e("tag out", ""+ dir);
}else {
dir.mkdir();
Log.e("tag out", "not exist");
}
File file = new File(dir, mTitle+".pdf");
try
{
Log.e("tag out", ""+ file);
out = new FileOutputStream(file);
in = new FileInputStream (new File(mPath));
Log.e("tag In", ""+ in);
copyFile(in, out);
in.close();
in = null;
out.flush();
out.close();
out = null;
} catch (Exception e)
{
Log.e("tag out", ""+ out);
Log.e("tag In", ""+ in);
Log.e("tag", e.getMessage());
Log.e("tag", ""+file);
Log.i("tag",""+sdcard.getAbsolutePath() + "A_level");
}
}
private void copyFile(InputStream in, OutputStream out) throws IOException
{
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1)
{
out.write(buffer, 0, read);
}
}

Categories

Resources