以编程方式从Android清单中禁用意图过滤器

9
在我的活动中,我有一个 Web 视图,在 manifest.xml 中,我声明了以下意图过滤器:
 <activity
        android:name=".ui.socialNetwork.MySocialNetworkActivity"
        android:configChanges="orientation|screenSize"
        android:process=":fb"
        android:screenOrientation="portrait" >

    </activity>

    <activity-alias
        android:targetActivity=".ui.socialNetwork.MySocialNetworkActivity"
        android:name=".AliasMySocialNetworkActivity"
        android:label="@string/app_name">
        <intent-filter>
            <action android:name="android.intent.action.PROCESS_TEXT" />
            <category android:name="android.intent.category.DEFAULT" />
            <data android:mimeType="text/plain" />
        </intent-filter>
    </activity-alias>

这不是启动器活动。

这里使用的意图过滤器是为了在Web视图长按时复制粘贴工具栏。这个功能很好用。

除此之外,我想使用Webview.setOnLongClickListener()添加其他选项,并像这样实现。

webView = (WebView) findViewById(R.id.webview);

PackageManager pm = getApplicationContext().getPackageManager();
    ComponentName compName =
            new ComponentName(getPackageName(), getPackageName() + ".AliasMySocialNetworkActivity");
    pm.setComponentEnabledSetting(
            compName,
            PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
            PackageManager.DONT_KILL_APP);

    webView.setOnLongClickListener(new View.OnLongClickListener() {
        public boolean onLongClick(View v) {
            WebView.HitTestResult hitResult = null;
            hitResult = webView.getHitTestResult();
            if (hitResult != null && hitResult.getExtra() != null) {
                final String hitRes = hitResult.getExtra();
                if (hitResult.getType() == WebView.HitTestResult.IMAGE_TYPE || hitResult.getType() == WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
                    Intent ImageSaveIntent = new Intent(getApplicationContext(), SaveImage.class);
                    ImageSaveIntent.putExtra("putImage", hitRes);
                    startActivity(ImageSaveIntent);
                }
                if (hitResult.getType() != WebView.HitTestResult.IMAGE_TYPE || hitResult.getType() != WebView.HitTestResult.SRC_IMAGE_ANCHOR_TYPE) {
                    PackageManager pm = getApplicationContext().getPackageManager();
                    ComponentName compName =
                            new ComponentName(getPackageName(), getPackageName() + ".AliasMySocialNetworkActivity");
                    pm.setComponentEnabledSetting(
                            compName,
                            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                            PackageManager.DONT_KILL_APP);
                                       }
            }
            return true;
        }
    });

我的问题是:
  1. 仅使用Intent Filter,不使用webview.setOnLongClickListener(),我可以复制粘贴webview中的文本。
  2. 仅使用webview.setOnLongClickListener(),我可以进行我的附加选项,并且它能够正常工作。
  3. 如果同时实现Intent Filter和webview.setOnLongClickListener(),则无法从webview中复制粘贴文本。webview.setOnLongClickListener()将正常工作。在这里,我理解这两个功能都依赖于长按事件, 但我希望两者都能一起工作。
我搜索了Webview.HitResult选项,想寻找TextType选项,但没有找到相应的选项。 https://developer.android.com/reference/android/webkit/WebView.HitTestResult.html

使用触摸监听器和手势监听器,并在想要复制粘贴时返回false,在想要执行自定义任务时返回true。 - Mohammed Atif
4个回答

12
你可以使用Activity Alias来实现这一点(以编程方式禁用Android清单中的意图过滤器):
1)在AndroidManifest.xml中将(例如AliasMySocialNetworkActivity)添加到MySocialNetworkActivity中,并将您的intent-filter移动到它们。它看起来会像这样:
         <activity-alias
            android:targetActivity=".MySocialNetworkActivity"
            android:name=".AliasMySocialNetworkActivity"
            android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.PROCESS_TEXT" />
                <category android:name="android.intent.category.DEFAULT" />
                <data android:mimeType="text/plain" />
             </intent-filter>
        </activity-alias>

2) 将以下代码添加到需要抑制别名活动中的 intent-filter 时使用

PackageManager pm = getApplicationContext().getPackageManager();
        ComponentName compName =
                new ComponentName(getPackageName(), getPackageName() + ".AliasMySocialNetworkActivity");
        pm.setComponentEnabledSetting(
                compName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

3) 需要时恢复 intent-filter:

PackageManager pm = getApplicationContext().getPackageManager();
    ComponentName compName =
            new ComponentName(getPackageName(), getPackageName() + ".AliasMySocialNetworkActivity");
    pm.setComponentEnabledSetting(
            compName,
            PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
            PackageManager.DONT_KILL_APP);

更多细节请参见这个那个答案。

更新

实际上您不需要别名,只需使用PackageManager.COMPONENT_ENABLED_STATE_DISABLED/PackageManager.COMPONENT_ENABLED_STATE_ENABLED

PackageManager pm = getApplicationContext().getPackageManager();
        ComponentName compName =
                new ComponentName(getPackageName(), getPackageName() + ".MySocialNetworkActivity");
        pm.setComponentEnabledSetting(
                compName,
                PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
                PackageManager.DONT_KILL_APP);

感谢 @pskink,直接在您的活动上执行。


1
setComponentEnabledSetting需要activity-alias吗? - pskink
1
我需要为写第二点创建另一个活动吗?还是我必须在我的MySocialNetworkActivity活动中编写? - Praveen Kumar
1
您不需要创建任何其他活动。即使是别名,@pskink - 正确的。请查看更新的答案。 - Andrii Omelchenko
有时候它会崩溃,显示错误信息"无法找到显式活动类{com.ylb.android/com.ylb.android.ui.socialNetwork.MySocialNetworkActivity};您在AndroidManifest.xml中声明了这个活动吗?" - Praveen Kumar
让我们在聊天中继续这个讨论 - Praveen Kumar
显示剩余12条评论

2
我成功实现了这个功能,但在将我的应用程序升级为Marshmallow支持时遇到了问题。
动态地无法从清单组件中删除IntentFilter。
如果您正在使用Marmalade / Native语言(如C和C ++(NDK)),则可以禁用IntentFilter组件,但在平台升级后(例如从Kitkat到LollyPop),会出现问题。
在developer.android.com的任何页面上,android社区都不建议进行此更改。
一个解决方案可能是:
  String packageName = getPackageName();
    try {
        PackageInfo p = getApplicationContext().getPackageManager().getPackageInfo(packageName, PackageManager.GET_ACTIVITIES);
        for (ActivityInfo activityInfo : p.activities) {
            if(log.d()) log.d("ACT " + activityInfo.name+" "+activityInfo.packageName);
        }
    } catch (PackageManager.NameNotFoundException e) {
        e.printStackTrace();
    }

使用代码中的别名 "alias" 进行跳转

ComponentName componentWithoutTextFiles = new ComponentName(packageName, packageName".alias");


你能建议我根据我的代码将这段代码写在哪里吗? - Praveen Kumar
我是新手,如果您将其集成到我的代码中,那将非常有帮助。我对componentName属性感到困惑。在manifest.xml文件中创建activity alias是否必要? - Praveen Kumar
1
你能详细说明一下吗? - Praveen Kumar

2
在我的情况下,
AndroidManifest.xml中的代码
<activity-alias
        android:name="alias.Shortcut"
        android:icon="@drawable/shortcut_icon"
        android:label="@string/shortcut_text"
        android:targetActivity="com.myexample.shortcutexample.ShortcutActivity">
        <intent-filter>
            <action android:name="android.intent.action.CREATE_SHORTCUT" />
            <category android:name="android.intent.category.DEFAULT" />
        </intent-filter>
    </activity-alias>

禁用别名的代码

PackageManager pm = getApplicationContext().getPackageManager();
        ComponentName compName =
                new ComponentName(getPackageName(), getPackageName() + ".alias.Shortcut");
        pm.setComponentEnabledSetting(
                compName,
                PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
                PackageManager.DONT_KILL_APP);

当我尝试时

getPackageName() + ".alias.Shortcut"

我收到了一个错误信息:java.lang.IllegalArgumentException: 组件类com.myexample.shortcutexample.alias.Shortcut在com.myexample.shortcutexample中不存在

因此,我修改了我的代码:

ComponentName compName =
                new ComponentName(getPackageName(), "alias.Shortcut");

它像魔法一样运行良好。


这种策略在启用/禁用清单中的“元数据”标签方面是否同样有效呢?例如,实现了WebView的Web浏览器应用程序,为用户提供选择加入/退出Google度量收集的功能。 - AdamHurwitz

1

@Andrii Omelchenko的答案是正确的,但我想补充一点,如果您在build.gradle中为构建类型(例如debug变体)或构建flavor使用applicationIdSuffix参数(例如“.debug”后缀),它将无法正常工作,因为它无法在代码中找到您的组件。

问题在于当您指定:

<activity-alias
    android:targetActivity=".MySocialNetworkActivity"
    android:name=".AliasMySocialNetworkActivity" />

在名称开头看到点“.” - Android 将使用您的应用程序包名称作为前缀,不包括 applicationIdSuffix,因此您将获得例如 com.example.packagename但是在代码中,context.getPackageName() 将返回带有 applicationIdSuffix 的包名称! 因此,在这种情况下,它将无法找到组件。

有两个解决方案:

  • 指定完整的android:name,不要以"."开头。例如:"MySocialNetworkActivity"。
  • 使用变量"${applicationId}指定包名前缀,该变量包含应用的applicationIdSuffix(在清单文件中自动可用):

    <activity-alias
        android:targetActivity=".MySocialNetworkActivity"
        android:name="${applicationId}.AliasMySocialNetworkActivity" />
    

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