Обновите приложение без действий из другого приложения - PullRequest
0 голосов
/ 11 марта 2020

Итак, у меня есть приложение А, которое является основным приложением. И затем у меня есть приложение B, в нем нет никаких действий, и оно используется приложением A в качестве службы для определения позиции пользователей. Чтобы обновить приложение B (с помощью APK, отправленного с нашего сервера), я использовал намерение с ACTION_VIEW в качестве действия, запущенного из приложения A. Но так как оно устарело, это больше невозможно, поэтому я пытаюсь вместо этого используйте packageInstaller.

Я могу обновить приложение A с помощью packageInstaller, но когда я пытаюсь сделать то же самое с приложением B (обновить его из приложения A с помощью packageInstaller), я получил следующее сообщение:

I/ContentValues: 4, INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION: Failed to parse /data/app/vmdl157182288.tmp/package: AndroidManifest.xml

, где 4 - это константа для PackageInstaller.STATUS_FAILURE_INVALID.

. Вот как я устанавливаю обновление:

public static final String PACKAGE_INSTALLED_ACTION = "fr.whereIwork.SESSION_API_PACKAGE_INSTALLED";

PackageInstaller packageInstaller = this.owner.getPackageManager().getPackageInstaller();

PackageInstaller.SessionParams params = new PackageInstaller.SessionParams( PackageInstaller.SessionParams.MODE_FULL_INSTALL );

int sessionId;

try
{
    sessionId = packageInstaller.createSession( params );
    PackageInstaller.Session session = packageInstaller.openSession( sessionId );

    Context context = this.owner.getApplicationContext();

    try
    {
        OutputStream packageInSession = session.openWrite( "package", 0, -1 );

        InputStream input;
        Uri uri = Uri.parse( "file://" + this.appDirectory + this.apkFileName );
        input = context.getContentResolver().openInputStream( uri );

        if( input != null )
        {    
            byte[] buffer = new byte[ 16384 ];
            int n;

            while ( ( n = input.read( buffer ) ) >= 0 )
            {
                packageInSession.write( buffer, 0, n );
            }
        }
        else
        {
            throw new IOException ( "addApkToInstallSession" );
        }

        packageInSession.close(); // Need to close this stream.
        input.close();            // Need to close this stream.
    }
    catch ( Exception exception )
    {
        exception.printStackTrace();
    }

    Intent intent = new Intent( context, this.owner.getClass() );
    intent.setAction( PACKAGE_INSTALLED_ACTION );
    intent.setFlags( Intent.FLAG_ACTIVITY_SINGLE_TOP );

    PendingIntent pendingIntent = PendingIntent.getActivity( context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT );
    IntentSender statusReceiver = pendingIntent.getIntentSender();

    session.commit( statusReceiver );
}
catch ( IOException e )
{
    e.printStackTrace();
}

И вот что происходит, когда это делается:

public static final String PACKAGE_INSTALLED_ACTION = "fr.whereIwork.SESSION_API_PACKAGE_INSTALLED";

@Override
protected void onNewIntent( Intent intent )
{
    Bundle extras = intent.getExtras();

    if ( extras != null )
    {
        if ( PACKAGE_INSTALLED_ACTION.equals( intent.getAction() ) )
        {
            int status  = extras.getInt( PackageInstaller.EXTRA_STATUS );
            String message = extras.getString( PackageInstaller.EXTRA_STATUS_MESSAGE );

            switch ( status )
            {
                case PackageInstaller.STATUS_PENDING_USER_ACTION :
                Intent confirmIntent = ( Intent ) extras.get( Intent.EXTRA_INTENT );
                startActivity( confirmIntent );
                break;

                case PackageInstaller.STATUS_SUCCESS :
                Toast.makeText( this, "Install successfull !", Toast.LENGTH_SHORT ).show();
                break;

                case PackageInstaller.STATUS_FAILURE :
                case PackageInstaller.STATUS_FAILURE_ABORTED :
                case PackageInstaller.STATUS_FAILURE_BLOCKED :
                case PackageInstaller.STATUS_FAILURE_CONFLICT :
                case PackageInstaller.STATUS_FAILURE_INCOMPATIBLE :
                case PackageInstaller.STATUS_FAILURE_INVALID :
                case PackageInstaller.STATUS_FAILURE_STORAGE :
                Log.i( TAG, status + ", " + message ); // This is the log I talked about.
                break;

                default :
                Toast.makeText( this, "Install failed ! " + status, Toast.LENGTH_SHORT ).show();
            }
        }
    }
}

Теперь вот манифест из приложения A:

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

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true" />

    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS" />

    <application
        android:name=".NameOfOurApplicationA"
        android:allowBackup="true"
        android:hardwareAccelerated="true"
        android:icon="@drawable/ourLogo"
        android:label="@string/application_name"
        android:largeHeap="true"
        android:theme="@style/ourAwesomeStyle"
        android:vmSafeMode="true"
        tools:ignore="GoogleAppIndexingWarning"
        tools:replace="android:label" >

        /*some crazy stuffs*/

        <activity
            android:name=".Login"
            android:configChanges="keyboardHidden|orientation|screenSize"
            android:launchMode="singleTop" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

        /*some more crazy stuffs for a whole lot of activities*/

    </application>

</manifest>

И, наконец, манифест из приложения B:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    package="fr.whereIwork.appB">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_GPS" />
    <uses-permission android:name="android.permission.ACCESS_ASSISTED_GPS" />
    <uses-permission android:name="android.permission.LOCATION" />
    <uses-permission android:name="android.permission.WAKE_LOCK"/>

    <application
        android:icon="@drawable/ourLogo"
        android:label="@string/application_name"
        android:name=".NameOfOurApplicationB">

        /*some stuffs, but no activities*/

        <service android:enabled="true" android:name="fr.whereIwork.appB.LocalisationService"
            android:exported="true" android:process=":remote">
        </service>
    </application>

</manifest>

Есть еще несколько Манифест из библиотек, используемых обоими этими приложениями (и, по сути, еще двумя), но я не считаю, что они актуальны в этом случае (я могу ошибаться).

Я предполагаю, что Дело в том, что в приложении B нет активности, так или иначе, но я не могу найти работающего решение на net (похоже, это довольно частный случай). И он прекрасно работает при обновлении приложения А. Я в растерянности.

Любая помощь будет отличной, спасибо за чтение!

...