0

I would like to make a code that downloads .apk file from url and put it in external storage then launch the update . But I am facing a problem with Kitkat Devices ( Only tested with Emulators ) .

After making few researches I found out that It seems that Kitkat uses okhttp instead of the previous HTTPConnection implementation, or at least this is the case on Nexus devices with the official update.

LOG :

    W/dalvikvm: VFY: unable to find class referenced in signature (Ljava/nio/file/Path;)
VFY: unable to find class referenced in signature ([Ljava/nio/file/OpenOption;)
I/dalvikvm: Could not find method java.nio.file.Files.newOutputStream, referenced from method okio.Okio.sink
W/dalvikvm: VFY: unable to resolve static method 45672: Ljava/nio/file/Files;.newOutputStream (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Ljava/io/OutputStream;
D/dalvikvm: VFY: replacing opcode 0x71 at 0x000a
W/dalvikvm: VFY: unable to find class referenced in signature (Ljava/nio/file/Path;)
VFY: unable to find class referenced in signature ([Ljava/nio/file/OpenOption;)
I/dalvikvm: Could not find method java.nio.file.Files.newInputStream, referenced from method okio.Okio.source
W/dalvikvm: VFY: unable to resolve static method 45671: Ljava/nio/file/Files;.newInputStream (Ljava/nio/file/Path;[Ljava/nio/file/OpenOption;)Ljava/io/InputStream;
D/dalvikvm: VFY: replacing opcode 0x71 at 0x000a
I/update_statut: onFailure  : Connection closed by peer

By the way I am using Asyntask to download and past file in the background .

    private static Boolean isDownloaded = false ;
    private OkHttpClient client;


    public class update extends AsyncTask<String,String,String>{

    private Context context;

    update (Context context){
     this.context=context;
    }


        @Override
protected String doInBackground(String... sUrl) {
    String path = Environment.getExternalStorageDirectory() + "/download/" + "myapp.apk";
    DownloadFile("https://linktodownload.com/myapp.apk"); // URL example.
    return path;
}

    @Override
protected void onPostExecute(String path) {
              //////////// Install Downloaded Apk

        if (isDownloaded) {
            MimeTypeMap mime = MimeTypeMap.getSingleton();
            File newFile = new File(path);
            String ext = newFile.getName().substring(newFile.getName().lastIndexOf(".") + 1);
            String type = mime.getMimeTypeFromExtension(ext);
            try {
                Intent intent = new Intent();
                intent.setAction(Intent.ACTION_VIEW);
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                    Uri contentUri = FileProvider.getUriForFile(context, "com.mypackage.fileProvider", newFile);
                    intent.setDataAndType(contentUri, type);
                } else {
                    intent.setDataAndType(Uri.fromFile(newFile), type);
                }
                context.startActivity(intent);
            } catch (ActivityNotFoundException anfe) {
                Log.i("update_statut", "onPostExecute Error : " + anfe.getMessage());
            }
        }

    }   
}




    public void DownloadFile(String apkurl){

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, 110);
                Log.i("update_statut", "Request Permission WRITE_EXTERNAL_STORAGE , Allow Permissions & Restart App");
                isDownloaded=  false;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
                requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, 110);
                Log.i("update_statut", "Request Permission READ_EXTERNAL_STORAGE, Allow Permissions & Restart App");
                isDownloaded = false;
        }

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M &&
                checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED
                &&
                checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED)
        {
            Log.i("update_statut", "Granted Permission WRITE AND READ EXTERNAL_STORAGE");
            Write_File(apkurl);
        }

        else if(Build.VERSION.SDK_INT==21 || Build.VERSION.SDK_INT==22)
        {
            Log.i("update_statut", "Lolipop");
            Write_File(apkurl);
        }

        else if(Build.VERSION.SDK_INT <= 20){
            Log.i("update_statut", "KitKat");
                     /////// PROBLEM IN THIS CODE
            client = new OkHttpClient();
            Request request = new Request.Builder().url(apkurl).build();
            client.newCall(request).enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.i("update_statut","onFailure  : "+e.getMessage());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    if (response.isSuccessful()){
                        String PATH = Environment.getExternalStorageDirectory() + "/download/";
                        File file = new File(PATH);
                        File outputFile = new File(file, "myapp.apk");
                        FileOutputStream fos = new FileOutputStream(outputFile);
                        InputStream is = response.body().byteStream();
                        byte[] buffer = new byte[1024];
                        int len1 = 0;
                        while ((len1 = is.read(buffer)) != -1) {
                            fos.write(buffer, 0, len1);
                        }
                        fos.close();
                        is.close();
                        isDownloaded = true;
                        Log.i("update_statut", "file Created");
                    }
                }
            });

        }
}




    public void Write_File(String apkurl){
    try {
        URL url = new URL(apkurl);
        URLConnection connection = url.openConnection();
        connection.connect();
        String PATH = Environment.getExternalStorageDirectory() + "/download/";
        File file = new File(PATH);
        if (!file.exists()) {
            file.mkdirs();
        }
        File outputFile = new File(file, "myapp.apk");
        FileOutputStream fos = new FileOutputStream(outputFile);
        InputStream is = connection.getInputStream();
        byte[] buffer = new byte[1024];
        int len1 = 0;
        while ((len1 = is.read(buffer)) != -1) {
            fos.write(buffer, 0, len1);
        }
        fos.close();
        is.close();
        isDownloaded = true;
    } catch(IOException e){
        Log.i("update_statut", "Download File Error : " + e.getMessage());
        isDownloaded = false;
    }
}

Here are Permissions Declared in Manifest :

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Also Provider Called in Manifest inside

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.mypackage.fileProvider"
        android:grantUriPermissions="true"
        android:exported="false">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>

Build.gradle implementation

    implementation 'com.squareup.okhttp3:okhttp:3.9.1'
Phantômaxx
  • 37,901
  • 21
  • 84
  • 115
Chaouki Anass
  • 937
  • 1
  • 10
  • 19
  • Use [this approach](https://stackoverflow.com/a/29012988/115145) for downloading binary files using OkHttp. As I suggested [previously](https://stackoverflow.com/questions/56877527/launch-apk-installer-kitkat#comment100305488_56877527), pull the downloaded APK off of the emulator (e.g., use Android Studio's Device File Explorer) and see if it was accurately downloaded (e.g., MD5 hash matches the original). – CommonsWare Jul 04 '19 at 11:59
  • @CommonsWare Thanks for your reply . Unfortunately , the method okhttp is useless because after I checked again in their website , it said : OkHttp works on Android 5.0+ (API level 21+) and on Java 8+. so its useless on Kitkat , is there any another http request do you suggest ? – Chaouki Anass Jul 04 '19 at 12:02
  • @CommonsWare the proof again is that OkHttp method I created is working very well on Marshmellow so It means there is no mistake in my code – Chaouki Anass Jul 04 '19 at 12:03
  • "the method okhttp is useless" -- you are using OkHttp already. You can tell that from your `implementation` statement and your Java code. "the proof again is that OkHttp method I created is working very well on Marshmellow" -- [the approach that I linked to](https://stackoverflow.com/a/29012988/115145) is faster, more reliable, and recommended by an OkHttp developer (Jesse Wilson). Also, pull the downloaded APK off of the emulator (e.g., use Android Studio's Device File Explorer) and see if it was accurately downloaded (e.g., MD5 hash matches the original). – CommonsWare Jul 04 '19 at 12:06
  • @CommonsWare thanks for your suggestion , but the http request always disconnects on kitkat so even the other code will not work , it always run onFailure : Connection closed by peer – Chaouki Anass Jul 04 '19 at 12:10
  • @CommonsWare as for the suggested method , is it gonna speed up the download time if working ? or it just reduces lines on coding – Chaouki Anass Jul 04 '19 at 12:11
  • @CommonsWare I said okhttp is useless because I tried it only for API19 , but for API 20 + , you see that Im using URLConnection instead – Chaouki Anass Jul 04 '19 at 12:12
  • Older versions of OkHttp, such as the 3.9.1 that you are using, work on older devices than API Level 19. The 5.0 limit is for the new 4.0.0 version of OkHttp. – CommonsWare Jul 04 '19 at 12:28
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/195993/discussion-between-chaouki-anass-and-commonsware). – Chaouki Anass Jul 04 '19 at 12:42

0 Answers0