HomeIsWhereThePcIs
HomeIsWhereThePcIs

Reputation: 1464

Parse error when parsing manifest

I made an application that attempts to download an APK update to internal storage from a remote server, and then install the update on the device. I tested it on a API24 device and everything works as expected.

Now I am testing it on a API 19 device (to test the part of the code pertaining to the old way of updating apps) and I keep getting "Parse error when parsing manifest". What puzzles me is that I can install the APK manually on the device and there is no parse error, so I don't think the problem is in the actual manifest file. I checked the length of the downloaded APK file in the internal storage and it appears to be fully downloaded. The code for downloading the APK is the same for all API versions.

Code:

pathToApk = getFilesDir() + "/update.apk";
try (InputStream is = response.body().byteStream();
     BufferedInputStream input = new BufferedInputStream(is);
     OutputStream os = new FileOutputStream(pathToApk)) {
         byte[] data = new byte[1024];
         int count;
         while ((count = input.read(data)) != -1) {
             os.write(data, 0, count);
         }

}

File toInstall = new File(pathToApk);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
  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);
}

Error:

W/PackageParser: Unable to read AndroidManifest.xml of /data/data/my.package.name/files/update.apk
  java.io.FileNotFoundException: AndroidManifest.xml
    at android.content.res.AssetManager.openXmlAssetNative(Native Method)
    at android.content.res.AssetManager.openXmlBlockAsset(AssetManager.java:501)
    at android.content.res.AssetManager.openXmlResourceParser(AssetManager.java:469)
    at android.content.pm.PackageParser.parsePackage(PackageParser.java:544)
    at com.android.packageinstaller.PackageUtil.getPackageInfo(PackageUtil.java:73)
    at com.android.packageinstaller.PackageInstallerActivity.onCreate(PackageInstallerActivity.java:467)
    at android.app.Activity.performCreate(Activity.java:5350)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1088)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2320)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2417)
    at android.app.ActivityThread.access$800(ActivityThread.java:151)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1342)
    at android.os.Handler.dispatchMessage(Handler.java:110)
    at android.os.Looper.loop(Looper.java:193)
    at android.app.ActivityThread.main(ActivityThread.java:5322)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:829)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:645)
    at dalvik.system.NativeStart.main(Native Method)
11-10 10:16:24.213 4140-4140/? W/PackageInstaller: Parse error when parsing manifest. Discontinuing installation

AndroidManifest.xml:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="my.package.name">

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.INTERNET" />

<application
    android:allowBackup="true"
    android:icon="@mipmap/ic_launcher"
    android:label="@string/app_name"
    android:supportsRtl="true"
    android:theme="@style/AppTheme">
    <activity
        android:name=".main.activities.UpdateActivity"
        android:screenOrientation="portrait">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
    </activity>

    <provider
        android:name="android.support.v4.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" />
    </provider>
</application>
</manifest>

EDIT

See my answer for solution.

Upvotes: 4

Views: 5173

Answers (3)

Jahangir Kabir
Jahangir Kabir

Reputation: 1843

Nicely described HERE

This is how i managed

if(Build.VERSION.SDK_INT < Build.VERSION_CODES.N){
            outputFile = File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS), "ABC.apk")
        } else {
            outputFile = File(filesDir, "ABC.apk")
        }

Upvotes: 0

HomeIsWhereThePcIs
HomeIsWhereThePcIs

Reputation: 1464

The problem was that the system could not read the APK from the private internal storage of my application on API<=23. The fix was pretty straightforward.

Changed this line:

OutputStream os = new FileOutputStream(pathToApk)

To this:

boolean old = Build.VERSION.SDK_INT < Build.VERSION_CODES.N;
OutputStream os = old ? 
    openFileOutput("update.apk", Context.MODE_WORLD_READABLE)
    : new FileOutputStream(pathToApk)

Upvotes: 1

KeLiuyue
KeLiuyue

Reputation: 8237

Add request here .

1.checkSelfPermission for Manifest.permission.READ_EXTERNAL_STORAGE

  • if granted , you can do readFile();

  • If not ,you should requestPermissions .

2.deal with onRequestPermissionsResult in your code

/**
 * permission code
 */
private static final int MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE = 1;

/**
 * requestPermissions and do something
 *
 */
public void requestRead() {
    if (ContextCompat.checkSelfPermission(this,
            Manifest.permission.READ_EXTERNAL_STORAGE)
            != PackageManager.PERMISSION_GRANTED) {

        ActivityCompat.requestPermissions(this,
                new String[]{Manifest.permission.READ_EXTERNAL_STORAGE},
                MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE);
    } else {
        readFile();
    }
}

/**
 * do you want to do
 */
public void readFile() {
    // do something
}

/**
 * onRequestPermissionsResult
 *
 * @param requestCode
 * @param permissions
 * @param grantResults
 */
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {

    if (requestCode == MY_PERMISSIONS_REQUEST_READ_EXTERNAL_STORAGE) {
        if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
            readFile();
        } else {
            // Permission Denied
            Toast.makeText(ToolbarActivity.this, "Permission Denied", Toast.LENGTH_SHORT).show();
        }
        return;
    }
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}

Add permission to the manifest

<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />

Upvotes: 0

Related Questions