CopyPastor

Detecting plagiarism made easy.

Score: 1; Reported for: Exact paragraph match Open both answers

Possible Plagiarism

Plagiarized on 2022-08-17
by Fahad Alkamli

Original Post

Original - Posted on 2016-10-19
by just\_user



            
Present in both answers; Present only in the new answer; Present only in the old answer;

After doing research and trying everything out, Here is my working code for android sdk 31:
1- created FileProvider and put it res/xml and named it "provider_paths":
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external" path="." /> </paths>
2- manifest:
<provider android:name="androidx.core.content.FileProvider" android:authorities="${applicationId}.provider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/provider_paths"/>

3-In the main activity I have a function to download the apk from a server and receive the file and launch an installation intent to install the new version:
void checkUpdate() { try{ //check if file exists delete it File file=new File("/sdcard/Download/app-debug.apk"); if(file.exists()) { file.delete(); Log.d(TAG,"Update file exists, Deleting it!"); } int versionCode = BuildConfig.VERSION_CODE; String url="https://Website.com/index.php?version="+versionCode; Log.d(TAG,url); OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(20, TimeUnit.SECONDS) .writeTimeout(20, TimeUnit.SECONDS) .readTimeout(20, TimeUnit.SECONDS) .build(); Request request = new Request.Builder() .url(url) .build(); Response response = null; response = client.newCall(request).execute(); if(response.code()!=200) { runOnUiThread(() -> Toast.makeText(getApplicationContext(),"No update found",Toast.LENGTH_LONG).show()); return; } //downloading the file InputStream is = response.body().byteStream(); BufferedInputStream input = new BufferedInputStream(is); String strRootPathInternalStorage = Environment.getExternalStorageDirectory().toString(); String path = strRootPathInternalStorage+"/"+Environment.DIRECTORY_DOWNLOADS+"/app-debug.apk"; Log.d(TAG,path); ResponseBody body = response.body(); long contentLength = body.contentLength(); Log.d(TAG,""+contentLength); BufferedSource source = body.source(); BufferedSink sink = null; if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) { sink = Okio.buffer(Okio.sink(Paths.get(path))); }else { Log.e(TAG,"Check this"); } Buffer sinkBuffer = sink.buffer(); long totalBytesRead = 0; int bufferSize = 8 * 1024; for (long bytesRead; (bytesRead = source.read(sinkBuffer, bufferSize)) != -1; ) { sink.emit(); totalBytesRead += bytesRead; } sink.flush(); sink.close(); source.close(); //finished downloading the file start installing runOnUiThread(() -> { try { File fileApkToInstall = new File("/sdcard/Download/app-debug.apk"); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri apkUri = FileProvider.getUriForFile(MainActivity.this, BuildConfig.APPLICATION_ID + ".provider", fileApkToInstall); Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.setData(apkUri); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); MainActivity.this.startActivity(intent); } else { Uri apkUri = Uri.fromFile(fileApkToInstall); Intent intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); MainActivity.this.startActivity(intent); } } catch (Exception e) { e.printStackTrace(); } }); }catch (Exception e) { e.printStackTrace(); } } 4- the website update logic is to get the current version from the app and check in the server to see if it's the last version if yes than return 404 or something similar and if no than return the apk file.
After a lot of trying I have been able to solve this by creating different Intents for anything lower than Nougat as using the FileProvider to create an install intent with Android Versions before Nougat causes the error:
ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }
While using a normal Uri on Android Nougat creates the following error:
FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()
My solution which is working for me with Android N on the emulator and a phone running Android M.
File toInstall = new File(appDirectory, appName + ".apk"); Intent intent; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", toInstall); intent = new Intent(Intent.ACTION_INSTALL_PACKAGE); intent.setData(apkUri); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); } else { Uri apkUri = Uri.fromFile(toInstall); intent = new Intent(Intent.ACTION_VIEW); intent.setDataAndType(apkUri, "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); } activity.startActivity(intent);
**UPDATE FOR Android Nougat 7.1:**
You also need to add the permission REQUEST_INSTALL_PACKAGES in your manifest. Its available from Api Level 23 (Android 6.0 Marshmallow) and required from Level 25 (Android 7.1 Nougat).
**UPDATE:**
Remember to request the permissions for read and write to external storage if the file you try to install is on the external storage. And also to set up a correct FileProvider for Android Nougat and above.
First check if you have write permission by calling `canReadWriteExternal()` below, if not call `requestPermission()` before:
private static final int REQUEST_WRITE_PERMISSION = 786;
@Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED) Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show(); }
private void requestPermission() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION); }
private boolean canReadWriteExternal() { return Build.VERSION.SDK_INT < Build.VERSION_CODES.M || ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED; }
Here is an example of a file provider for the Download folder on the external storage. **AndroidManifest.xml**:
<application ... > ...
<provider android:name="android.support.v4.content.FileProvider" android:authorities="${applicationId}.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider> </application>
**resources/xml/filepaths.xml**:
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="external_download" path="Download"/> </paths>
If you get an error while installing the .apk saying something like "There is a problem parsing the package." it could be that you haven't asked for the read/write permission or the file you try to install doesn't exist or is corrupt.
**UPDATE FOR Android Oreo 8.0:**
You have to check if current application is allowed to install the APK on Android Oreo 8.0 or above.
You can check if your app is allowed to install APK by using [canRequestPackageInstalls][1] method of PackageManager class. If it returns false, then you can launch intent with [ACTION_MANAGE_UNKNOWN_APP_SOURCES][2] action to launch settings dialog where user can allow the app to install APKs.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !getPackageManager().canRequestPackageInstalls()) { Intent unknownAppSourceIntent = new Intent() .setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) .setData(Uri.parse(String.format("package:%s", getPackageName()))); unknownAppSourceDialog.launch(unknownAppSourceIntent); } else { // App already have the permission to install so launch the APK installation. startActivity(intent); }
Make sure you add the following code to your activity to receive the result of intent.
ActivityResultLauncher<Intent> unknownAppSourceDialog = registerForActivityResult( new ActivityResultContracts.StartActivityForResult(), result -> { if (result.getResultCode() == Activity.RESULT_OK) { // User has allowed app to install APKs // so we can now launch APK installation. startActivity(intent); } });
[1]: https://developer.android.com/reference/android/content/pm/PackageManager#canRequestPackageInstalls() [2]: https://developer.android.com/reference/android/provider/Settings#ACTION_MANAGE_UNKNOWN_APP_SOURCES

        
Present in both answers; Present only in the new answer; Present only in the old answer;