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.
Related
I'm currently developing an app that need to check if there is a new version available.
I found how to download the apk and install it.
But i cant figure out how to get the APK URL.
I'm using the testing (alpha) environment, so my app is not published yet, where can i get the APK URL.
Here's the code for download:
try {
URL url = new URL(apkurl);
HttpURLConnection c = (HttpURLConnection) url.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.connect();
String PATH = Environment.getExternalStorageDirectory() + "/download/";
File file = new File(PATH);
file.mkdirs();
File outputFile = new File(file, "app.apk");
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();//till here, it works fine - .apk is download to my sdcard in download file
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(intent);
} catch (IOException e) {
Toast.makeText(getApplicationContext(), "Update error!", Toast.LENGTH_LONG).show();
}
How can i get the APK URL?
you have to create it yourself. create folder and name a file to it. as you are doing in the code. like
String PATH = Environment.getExternalStorageDirectory() + "/download/";
File file = new File(PATH);
file.mkdirs();
File outputFile = new File(file, "app.apk");
to create your own one do this.
Add this permission in Manifest,
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
and to create folder with name of your file
File folder = new File(context.getCacheDir().getPath() + "/files/myFolder");
folder.mkdirs();
File f= new File(folder, "app.apk");
if (!folder .exists()){
folder.create();
}
where you can put your apk
If you are using Alpha (testing) environment. This is the Url:
https://play.google.com/apps/testing/com.yourdomain.package
But, your APK will not be available to public, it is ONLY for activated testers in the alpha section.
I am having one heck of a time with this new permission request in Android 6. My app worked fine, and then in the last two days it is force closing all the time. If I change the target SDK level to 22, it works fine, but of course Play Store wont let you downgrade the SDK.
I need these permissions.
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="com.android.vending.BILLING" />
After this I am not sure how to work the requesting, or new way of implementing the permissions part so the errors will stop. I have been working on this for hours and have googled and search endlessly. While alot of examples out there all tell me to do the same thing, I just cannot seem to get it write in Android Studio. Any help would be greatly appreciated.
Here is part of the code that was giving me issues.
public void exportSkin(View arg0) throws IOException {
if (type.equals("popular")) {
AssetManager assetManager = getAssets();
InputStream is = assetManager.open("skins/" + skinname + ".png");
// create a File object for the parent directory
File wallpaperDirectory = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).getPath() + "/SkinYourself/");
// have the object build the directory structure, if needed.
//noinspection ResultOfMethodCallIgnored
wallpaperDirectory.mkdirs();
// create a File object for the output file
File out = new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES) + "/SkinYourself/", "" + PopChar.character_name + ".png");
byte[] buffer = new byte[1024];
FileOutputStream fos = new FileOutputStream(out);
int read;
while ((read = is.read(buffer, 0, 1024)) >= 0) {
fos.write(buffer, 0, read);
}
fos.flush();
fos.close();
is.close();
}
if (type.equals("create")) {
String root = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString();
File myDir = new File(root + "/SkinYourself");
myDir.mkdirs();
String fname = "SkinYourself" + System.currentTimeMillis() / 1000 + ".png";
File file = new File(myDir, fname);
if (file.exists()) file.delete();
try {
FileOutputStream out = new FileOutputStream(file);
b.compress(Bitmap.CompressFormat.PNG, 100, out);
out.flush();
out.close();
} catch (Exception e) {
e.printStackTrace();
}
}
/*sendBroadcast(new Intent(
Intent.ACTION_MEDIA_MOUNTED,
Uri.parse("file://" + Environment.getExternalStorageDirectory())));
*/
Toast.makeText(MainActivity.this,
"Your skin has been saved to the SkinYourself folder check the info button on how to use it", Toast.LENGTH_LONG)
.show();
displayInterstitial();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Intent mediaScanIntent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
File f = new File("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES));
Uri contentUri = Uri.fromFile(f);
mediaScanIntent.setData(contentUri);
this.sendBroadcast(mediaScanIntent);
} else {
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://" + Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES))));
}
}
I'm trying to share an audio file from my res/raw folder. What I've done so far is:
Uri uri = Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.sound); //parse path to uri
Intent share = new Intent(Intent.ACTION_SEND); //share intent
share.setType("audio/*");
share.putExtra(Intent.EXTRA_STREAM, uri);
startActivity(Intent.createChooser(share, "Share sound to"));
When I choose to share it on GMail, for example, it says something like "Failed to attach empty file". Looks like I'm not getting the right file path, so I'm basically sharing nothing. What am I doing wrong?
Any help would be much appreciated.
Copy the audio file from the resource to external storage and then share it:
InputStream inputStream;
FileOutputStream fileOutputStream;
try {
inputStream = getResources().openRawResource(R.raw.sound);
fileOutputStream = new FileOutputStream(
new File(Environment.getExternalStorageDirectory(), "sound.mp3"));
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) > 0) {
fileOutputStream.write(buffer, 0, length);
}
inputStream.close();
fileOutputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
Intent intent = new Intent(Intent.ACTION_SEND);
intent.putExtra(Intent.EXTRA_STREAM,
Uri.parse("file://" + Environment.getExternalStorageDirectory() + "/sound.mp3" ));
intent.setType("audio/*");
startActivity(Intent.createChooser(intent, "Share sound"));
Add WRITE_EXTERNAL_STORAGE permission to AndroidManifest.xml file:
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
What am I doing wrong?
Few apps handle android.resource Uri values correctly. Your choices are:
Drop the feature, or
Copy the data from the resource into a file, then use FileProvider, perhaps in conjunction with my LegacyCompatCursorWrapper, or
Use my StreamProvider, which can serve raw resources directly, or
Copy the data from the resource into a file, then use Uri.fromFile(), but this looks like it will stop working with the next version of Android, based on preliminary results from testing with the N Developer Preview
EDIT: It was causing a NullPointException. This is what was I doing:
File dest = Environment.getExternalStorageDirectory();
InputStream in = getResources().openRawResource(R.raw.sound);
try
{
OutputStream out = new FileOutputStream(new File(dest, "sound.mp3"));
byte[] buf = new byte[1024];
int len;
while ( (len = in.read(buf, 0, buf.length)) != -1){
out.write(buf, 0, len);
}
in.close();
out.close();
}catch (Exception e) {}
final Uri uri = FileProvider.getUriForFile(Soundboard.this, "myapp.folagor.miquel.folagor", dest); //NullPointerException right here!!
final Intent intent = ShareCompat.IntentBuilder.from(Soundboard.this)
.setType("audio/*")
.setSubject(getString(R.string.share_subject))
.setStream(uri)
.setChooserTitle(R.string.share_title)
.createChooserIntent()
.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivity(intent);
The code was just fine. The only problem was that on the Manifest's permisions, I had "WRITE_EXTERNAL_STORAGE" instead of "android.permissions.WRITE_EXTERNAL_STORAGE". So I was not having permision to write in the external storage, which caused a FileNotFoundException due to the lack of permision. Now it works fine!
I'm using the DownloadManager to download the apk from url. Download completes, I get the onReceive in my BroadcastReceiver for DownloadManager.ACTION_DOWNLOAD_COMPLETE.
Some Coding: I download the apk file from an url to the download directory.
DownloadManager.Request r = new DownloadManager.Request(mUri);
r.setDestinationInExternalPublicDir(Environment.DIRECTORY_DOWNLOADS, "myapp.apk");
r.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
DownloadManager dm = (DownloadManager) activity.getSystemService(Context.DOWNLOAD_SERVICE);
SharedPreferences mSharedPref = activity.getSharedPreferences("package", Context.MODE_PRIVATE);
mSharedPref.edit().putLong("downloadID", dm.enqueue(r)).commit();
onReceive
File apkFile = new File(Environment.DIRECTORY_DOWNLOADS + "myapp.apk");
Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
startActivity(promptInstall);
Problems:
The file is there, I want to execute it but I package-installer is not shown
Even though I see the file in my phones download folder, I if I want to install it there is no package-installer to choose
I'm not sure if I do the file and pathing stuff right..
I get an parsing error from android when I try to open the file
Someone got an idea please?
I recently had to do something like this, hope it helps:
EDIT: Couple of notes,
apkurl is a string to the download location.
Make the byte buffer big enough for your response
try {
String PATH = Environment.getExternalStorageDirectory() + "/download/";
File file = new File(PATH);
file.mkdirs();
// Create a file on the external storage under download
File outputFile = new File(file, "app.apk");
FileOutputStream fos = new FileOutputStream(outputFile);
HttpGet m_httpGet = null;
HttpResponse m_httpResponse = null;
// Create a http client with the parameters
HttpClient m_httpClient = setupHttpClient();
String result = null;
try {
// Create a get object
m_httpGet = new HttpGet(apkurl);
// Execute the html request
m_httpResponse = m_httpClient.execute(m_httpGet);
HttpEntity entity = m_httpResponse.getEntity();
// See if we get a response
if (entity != null) {
InputStream instream = entity.getContent();
byte[] buffer = new byte[1024];
// Write out the file
int len1 = 0;
while ((len1 = instream.read(buffer)) != -1) {
fos.write(buffer, 0, len1);
}
fos.close();
instream.close();// till here, it works fine - .apk is download to my sdcard in download file
}
} catch (ConnectTimeoutException cte) {
// Toast.makeText(MainApplication.m_context, "Connection Timeout", Toast.LENGTH_SHORT).show();
return false;
} catch (Exception e) {
return false;
} finally {
m_httpClient.getConnectionManager().closeExpiredConnections();
}
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(
Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk")),
"application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
MainApplication.getApp().getApplicationContext().startActivity(intent);
// System.exit(0);
} catch (IOException e) {
Debug.ERROR(CLASSNAME, METHODNAME, "Failed to update new apk");
return false;
} catch (Exception e1) {
Debug.ERROR(CLASSNAME, METHODNAME, "Failed to update new apk");
return false;
}
return true;
Make sure you have the android.permission.INSTALL_PACKAGES permission declared in your AndroidManifest.xml.
Then get your APK path:
File apkFile = new File(Environment.getExternalStorageDirectory() + "/download/" + "app.apk");
Now run the Intent:
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
All downloads you do with the device...
To clarify what I mean with "Downloads" here is a screenshot. This is the standart download folder for Android 5 on Nexus 4. When I click on the apk inside this, I dont get the prompt to install a .apk. Instead the HTML-Viewer or other useless stuff shows up to choose...
One possible mistake could be the DownloadManager.. maybe he "tags" the downloaded file wrong so its not interpreted as an apk file, I don't know... but I call
promptInstall.setDataAndType(Uri.fromFile(new File(Environment.getExternalStorageDirectory() + "/download/myapp.apk")), "application/vnd.android.package-archive");
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);
}
}