可以在运行时通过编程方式更新Android清单吗?

8

我想要实现的目标:

我正在创建一个应用程序,通过编程方式更改应用程序图标和应用程序名称。

我已经实现的内容:

我已经通过在Android清单中声明activity-alias来实现这一点,因为只有5个名称和图标可供选择。

我面临的问题:

如果您不知道名称的数量,并且必须以编程方式更新清单,则很难处理。

以下是我的代码:

AndroidManifest.xml

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

    <uses-permission android:name="com.android.launcher.permission.INSTALL_SHORTCUT" />
    <uses-permission android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".MainActivity"
            android:label="@string/app_name"
            android:theme="@style/AppTheme.NoActionBar">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

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

        <activity-alias android:label="@string/app_name1"
            android:icon="@drawable/ic_launcher"
            android:name=".MainActivity-Red"
            android:enabled="false"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias android:label="@string/app_name2"
            android:icon="@drawable/ic_launcher_1"
            android:name=".MainActivity-Pink"
            android:enabled="false"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias android:label="@string/app_name3"
            android:icon="@drawable/ic_launcher_2"
            android:name=".MainActivity-Blue"
            android:enabled="false"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>

        <activity-alias android:label="@string/app_name4"
            android:icon="@drawable/ic_launcher_3"
            android:name=".MainActivity-Grey"
            android:enabled="false"
            android:targetActivity=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity-alias>
    </application>
</manifest>

MainActivity.java文件中。
    img.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            if (view.getTag().equals(0)) {
                changeIcon("com.drawerstack.MainActivity-Red");
                removeIcon("com.drawerstack.MainActivity");
                removeIcon("com.drawerstack.MainActivity-Pink");
                removeIcon("com.drawerstack.MainActivity-Blue");
                removeIcon("com.drawerstack.MainActivity-Grey");
            } else if (view.getTag().equals(1)) {
                changeIcon("com.drawerstack.MainActivity-Pink");
                removeIcon("com.drawerstack.MainActivity-Blue");
                removeIcon("com.drawerstack.MainActivity-Grey");
                removeIcon("com.drawerstack.MainActivity-Red");
                removeIcon("com.drawerstack.MainActivity");
            } else if (view.getTag().equals(2)) {
                changeIcon("com.drawerstack.MainActivity-Blue");
                removeIcon("com.drawerstack.MainActivity-Pink");
                removeIcon("com.drawerstack.MainActivity-Grey");
                removeIcon("com.drawerstack.MainActivity-Red");
                removeIcon("com.drawerstack.MainActivity");
            } else if (view.getTag().equals(3)) {
                changeIcon("com.drawerstack.MainActivity-Grey");
                removeIcon("com.drawerstack.MainActivity-Pink");
                removeIcon("com.drawerstack.MainActivity-Red");
                removeIcon("com.drawerstack.MainActivity-Blue");
                removeIcon("com.drawerstack.MainActivity");
            }
        }
    });


private void changeIcon(final String pkgName) {

    doAsynchronousTask = new TimerTask() {
        @Override
        public void run() {
            // TODO Auto-generated method stub
            Date now = new Date();
            if(now.after(afterDate)){
                timer.cancel();
                Common.dismissProgressDialog(MainActivity.this);
                finish();
            }
        }
    };
    timer.schedule(doAsynchronousTask, 0, 50000);

    Common.loadProgressDialog(MainActivity.this,false);
    getPackageManager().setComponentEnabledSetting(
            new ComponentName("com.drawerstack", pkgName),
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
}


private void removeIcon(String removePkg) {
        getPackageManager().setComponentEnabledSetting(
                new ComponentName("com.drawerstack", removePkg),
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP);
}

1
假设你的问题是标题中的“是否可以通过编程方式更新Android清单?”,答案是不行,无法通过编程方式实现。 - azizbekian
@azizbekian 连一种实现的方法都没有吗?? - MashukKhan
2
你可以在清单文件中启用/禁用已声明的组件,但不可以添加或删除内容。正如其名称所示,这是一个清单文件,在安装您的应用程序时,系统会“读”该文件。因此,您要在该清单文件中声明应用程序的接口,并且稍后无法更改它(除非使用另一个清单重新安装应用程序)。 - azizbekian
我会将那些评论发布为答案。 - azizbekian
“除非您使用另一个清单重新安装应用程序”,这真的可能吗? - MashukKhan
如果你更改了你的清单文件并安装了新的apk,那就是我指的。 - azizbekian
2个回答

13

假设你的问题是标题中的一个:

是否可以以编程方式更新Android清单?

答案是否定的,不能以编程方式进行更新。

您可以启用/禁用在清单中声明的组件,但是您无法添加或删除其中的内容,因为它是一个清单文件,系统在安装您的应用程序时会“读取”它。因此,您在该清单中声明了应用程序的接口,稍后您无法更改它,除非使用另一个清单重新安装应用程序。

假设系统允许您这样做,那么您将以动态方式向您的清单添加某些权限,而用户在从Play商店下载您的应用程序时尚未批准该权限。


1
你可以通过使用以下代码来更改Admob或任何字符串的清单元数据值:
package com.asdf.loanapp;

import android.os.Build;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class ModifyManifest {

static String readFileString;

public static void main(String[] args) {
    // Specify the path to the         
 AndroidManifest.xml file
    String manifestFilePath =     "/path/to/AndroidManifest.xml";

    // Specify the name of the metadata element     you want to modify
    String metadataName = "your_metadata_name";

    // Specify the new metadata value
    String newMetadataValue =     "place_your_admob_string_here";

        try {
        // Read the contents of the     AndroidManifest.xml file
            String manifestContent =     readFile(manifestFilePath);

            // Modify the metadata value
            manifestContent =     modifyMetadata(manifestContent, metadataName,     newMetadataValue);

            // Save the modified content back     to the file
            saveFile(manifestContent, manifestFilePath);

            System.out.println("Metadata in     AndroidManifest.xml modified successfully.");
        } catch (IOException e) {
            e.printStackTrace();
    }
    }

    // Read the contents of a file

    private static String readFile(String     filePath) throws IOException {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            readFileString = new     String(Files.readAllBytes(Paths.get(filePath)));
        }
        return readFileString;
    }

    // Modify the metadata value in the     AndroidManifest.xml
    private static String modifyMetadata(String     manifestContent, String metadataName, String newMetadataValue) {
        // Find and replace the metadata value
        String oldMetadataTag = "<meta-data     android:name=\"" + metadataName + "\"";
        int startIndex =     manifestContent.indexOf(oldMetadataTag);
        if (startIndex != -1) {
            int endIndex =     manifestContent.indexOf(">", startIndex);
            if (endIndex != -1) {
                // Extract the existing value
                String existingMetadataTag =     manifestContent.substring(startIndex, endIndex);
                String existingValue =     extractMetadataValue(existingMetadataTag);
               

                // Create the new metadata tag with the modified value
                String newMetadataTag = "<meta-data android:name=\"" + metadataName + "\"     android:value=\"" + newMetadataValue + "\" />";

                // Replace the old metadata tag     with the new one
                manifestContent =     manifestContent.replace(existingMetadataTag,     newMetadataTag);
            }
        }
        return manifestContent;
    }

    // Extract the value attribute from a     metadata tag
        private static String     extractMetadataValue(String metadataTag) {
        Pattern pattern =     Pattern.compile("android:value=\"([^\"]*)\"");
        Matcher matcher =     pattern.matcher(metadataTag);
        if (matcher.find()) {
            return matcher.group(1);
        }
        return null;
    }

    // Save modified content back to the file
    private static void saveFile(String     content, String filePath) throws IOException {
        if (Build.VERSION.SDK_INT >=     Build.VERSION_CODES.O) {
            Files.write(Paths.get(filePath),     content.getBytes());
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接