尝试 UNINSTALL_SHORTCUT 但快捷方式不会消失

2024-03-27

我创建了一个测试活动,它在 Android 主屏幕上安装了它自己的快捷方式。当您单击按钮时,活动应该删除它刚刚创建的相同快捷方式。但是,我似乎没有做任何事情来删除快捷方式。

下面是 Java 代码 (ShortcutTest.java):

import java.net.URISyntaxException;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;

public class ShortcutTest extends Activity {
    String shortcutUri;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        addShortcut(getBaseContext());

        Button button = (Button)findViewById(R.id.Button01);
        button.setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                removeShortcut(getBaseContext());
                finish();
            }
        });
    }

    public void addShortcut(Context context) {
        Intent shortcutIntent = new Intent();
        shortcutIntent.setClassName("com.telespree.android.client", "com.telespree.android.client.ShortcutTest");
        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        shortcutIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);

        Intent intent = new Intent();
        intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "ShortcutTest");
        intent.putExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, Intent.ShortcutIconResource.fromContext(context, R.drawable.icon));
        intent.setAction("com.android.launcher.action.INSTALL_SHORTCUT");
        shortcutUri = intent.toUri(MODE_WORLD_WRITEABLE);
        context.sendBroadcast(intent);
    }

    public void removeShortcut(Context context) {
        Intent intent = null;
        try {
            intent = Intent.parseUri(shortcutUri, 0);
        } catch (URISyntaxException e) {
        }
        intent.setAction("com.android.launcher.permission.UNINSTALL_SHORTCUT");
        context.sendBroadcast(intent);
    }
}

这是清单:

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

      <permission
        android:name="com.android.launcher.permission.UNINSTALL_SHORTCUT"
        android:permissionGroup="android.permission-group.SYSTEM_TOOLS"
        android:protectionLevel="normal"
        />

    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".ShortcutTest"
                  android:label="@string/app_name" android:theme="@android:style/Theme.Translucent">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>

    </application>

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

    <uses-sdk android:minSdkVersion="7" />

</manifest> 

我几乎肯定存在某种权限问题,尽管我在互联网上看到其他帖子表明这应该是可能的。

任何意见是极大的赞赏。

Thanks.


已弃用;仅为历史目的保留

This answer was posted in 2014, when the described method relied on functionality that existed in most Android devices. However, as mentioned by Adrian-Costin Țundrea https://stackoverflow.com/a/33731620/3372061, this functionality was removed https://android.googlesource.com/platform/packages/apps/Launcher3/+/e9909f58c2b235f8066295c4faa6a00415968ae7 a couple of years ago from Launcher3, which is the AOSP launcher upon which the Google Now Launcher is based1 https://www.reddit.com/r/AndroidQuestions/comments/3wcfuj/google_now_app_called_launcher3_is_this_normal/cxv9va6/. The commit message said:

由于其脆弱的设计而取消了支撑。删除快捷方式 导致完全重新加载。而且我们没有任何所有者的概念,所以 任何应用程序都可以删除任何快捷方式。

截至 2017 年 3 月,该启动器也正在逐步淘汰 http://www.androidpolice.com/2017/02/03/google-will-discontinue-google-now-launcher-coming-weeks/支持“Google搜索启动器服务”,这意味着制造商可以将某个Google库集成到自己的自定义启动器中,而不是依赖于Google提供的标准化启动器。

考虑到每个制造商都可以自由地以他们想要的方式实现他们的启动器,并且假设其中一些基于 Launcher3,则很难判断下面的方法适用于哪些设备,因为 Launcher3 甚至可以在某些设备上运行安卓4.1 https://f-droid.org/wiki/page/com.android.launcher3设备,其中包括仍在使用的最旧设备 https://developer.android.com/about/dashboards/index.html#Platform.


问候!

我刚刚处理了同样的问题,并想在成功解决后分享我的经验。tl;dr - 跳到下面的“结论”。

一些背景:

在开发应用程序的“下一个版本”时,需要更改默认入口点(即重命名“主要活动”)。这是皱起眉头因为从旧版本升级的用户仍然会使用旧的快捷方式,指向错误的位置。为了尽可能避免出现问题,在第一次启动时,在他们不知情的情况下,旧的快捷方式被替换为新的快捷方式。

第 1 步:设置新的入口点

这是最简单的部分。声明入口点唯一重要的事情要做就是把下面的<action ...>在清单内适当的活动声明中标记:

<activity
    android:name="YOUR_PACKAGE_NAME.YOUR_ACTIVITY_NAME"
    android:label="@string/app_name">
    <intent-filter>
        <action android:name="android.intent.action.MAIN" />
    </intent-filter>
</activity>

什么是切入点default从某种意义上说,是启动器快捷方式指向它。这就是为什么开发人员通常也会将其包含在<intent-filter>:

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

应该指出的是,每项活动都包含此内容<intent-filter> will在您的应用程序抽屉中创建一个项目 - 这就是为什么在大多数情况下您只需要 1 个实例。

第 2 步:弄清楚旧快捷方式是如何工作的

拥有 root 设备后,我可以访问存储启动器/主屏幕/桌面项目的数据库表(参见 SQLite 条目的图片) http://imageshack.com/a/img713/3677/o2u4.png它位于:

/data/data/com.android.launcher/databases/launcher.db -> SELECT * FROM favorites`

这是图像中突出显示的条目的更易读的版本:

#Intent;
    action=android.intent.action.MAIN;
    category=android.intent.category.LAUNCHER;
    launchFlags=0x10200000;
    package=gidutz.soft.bluecard;
    component=gidutz.soft.bluecard/.LoadingScreen;
 end

请注意0x10200000- 这在中进行了解释第 4 步 - 尝试 1 below.

第 3 步:找出快捷方式卸载程序的期望

第 38-42 行UninstallShortcutReceiver.java告诉我们:

Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);

if (intent != null && name != null) { ... }

这意味着“卸载意图”必须具有both Intent.EXTRA_SHORTCUT_INTENT and Intent.EXTRA_SHORTCUT_NAME否则根本不会考虑执行。

第四步:找到正确的语法

这是一个试错但结局皆大欢喜的案例。

尝试 1:重构意图

Intent oldShortcutIntent = new Intent();
oldShortcutIntent.setAction(Intent.ACTION_MAIN);
oldShortcutIntent.addCategory(Intent.CATEGORY_LAUNCHER);
oldShortcutIntent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED +
                           Intent.FLAG_ACTIVITY_NEW_TASK);
oldShortcutIntent.setPackage("gidutz.soft.bluecard");
oldShortcutIntent.setComponent(new ComponentName("gidutz.soft.bluecard",
                                                     ".LoadingScreen"));
//  The above line is equivalent to:
Intent oldShortcutIntent = new Intent(getApplicationContext(),LoadingScreen.class);
Intent uninstaller = new Intent();
uninstaller.putExtra(Intent.EXTRA_SHORTCUT_INTENT, oldShortcutIntent);
uninstaller.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");
uninstaller.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(uninstaller);

Result:图标未删除。 这0x10200000实际上是两个参数的总和,如所解释的here http://developer.android.com/reference/android/content/Intent.html#FLAG_ACTIVITY_NEW_TASK.

尝试 2:使用 Viralpatel 中的原样代码

Intent shortcutIntent = new Intent(getApplicationContext(),LoadingScreen.class);
shortcutIntent.setAction(Intent.ACTION_MAIN);

Intent addIntent = new Intent();
addIntent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
addIntent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");

addIntent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(addIntent);

Result:图标未删除。

尝试3:“暴力”

尝试完全按照 launcher.db 中显示的方式复制粘贴意图:

Intent intent = new Intent();
String oldShortcutUri = "#Intent;action=android.intent.action.MAIN;category=android.intent.category.LAUNCHER;launchFlags=0x10200000;package=gidutz.soft.bluecard;component=gidutz.soft.bluecard/.LoadingScreen;end";
try {
    Intent altShortcutIntent  = Intent.parseUri(oldShortcutUri,0);
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, altShortcutIntent);
    intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "Blue Card");
} catch (URISyntaxException e) {
}
intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
getApplicationContext().sendBroadcast(intent);

Result:图标已删除!!

综上所述

  1. 确保您的“图标卸载程序”意图使用与创建您要删除的图标完全相同的 URI,方法是存储用于创建图标的 URI,或者从launcher.db.
  2. 等待大约 2-3 秒,“图标已删除”吐司就会出现。

Sources

1) 本指南位于 Viralpatel.net http://viralpatel.net/blogs/android-install-uninstall-shortcut-example/

2) Google 的 UninstallShortcutReceiver.java 实现 https://android.googlesource.com/platform/packages/apps/Launcher/+/master/src/com/android/launcher/UninstallShortcutReceiver.java

3) xda 开发者的这个帖子 http://forum.xda-developers.com/showthread.php?t=543882

P.S.

为了模拟和调试 Google Play 更新(保留旧的快捷方式),我执行了以下操作:

  1. 从商店安装了旧版本的应用程序 - 带有“旧快捷方式”的图标自动放置在我的屏幕上。
  2. 使用 Total Commander 备份我的 launcher.db。
  3. 通过我的 IDE 安装新版本(您也可以使用 .apk)-“旧快捷方式”现在消失了。
  4. 打开 Total Commander 并将其最小化(以便在“ALT-TAB”菜单中提供快捷方式)。
  5. 转到“设备设置”>>“应用程序”>>“全部”,找到我的启动器(对我来说,它是“Trebuchet”,因为我使用的是 CM11)并且力停止 it.
  6. ALT-TAB 进入 Total Commander 并恢复数据库。
  7. 单击硬件“主页”按钮重新启动启动器。
  8. 中提琴!旧的快捷方式现已恢复。

注 1:回想起来,使用从数据库获取的 URI 手动创建旧快捷方式可能更容易,而不是经历所有备份和强制停止的考验。

注意2:我还没有尝试使用此方法删除属于其他应用程序的图标,但它可能足够疯狂,可以工作。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

尝试 UNINSTALL_SHORTCUT 但快捷方式不会消失 的相关文章

随机推荐

  • 我可以转换对象并访问 C++ 中的私有数据成员吗?

    我想访问类中的私有数据成员 类中没有成员函数来访问私有数据成员 这是私人的 我想上这门课 想知道如何打开它 一种方法是复制类的声明 将私有成员设为公共 然后将新类称为 some else 然后我重新解释转换并复制原始对象 这有效 但我想要一
  • 只做如果一天...批处理文件

    你好 我有一个批处理文件 如下所示 if day monday tuesday wednesday thursday friday goto yes else goto no 现在我知道第一行不起作用 我真正想要发生的事情 它会自动检查今天
  • 如何让通用ListView只显示用户的列表?

    我是 Django 新手 这是我第一次使用基于类的视图 我想使用通用 ListView 来显示用户拥有的 表 列表 到目前为止 我已经让它显示数据库中的所有表 但我只希望它显示登录用户的表格 这就是我的观点 from django shor
  • gcc -Wpadded 不提供任何警告

    我正在尝试使用 gcc 的 Wpadded 选项来了解 gcc 是否可以帮助我找出结构是否已填充 这是下面的代码 include
  • 从 R 中的 ca.jo 中的 Johannsen 协整方法估计 t 统计量

    我正在研究 R 中 vars 库中的小插图工作示例 我了解小插图中的大部分示例 除了小插图的表 5here https cran r project org web packages vars vignettes vars pdf 运行以下
  • Haskell 中具有多个参数的部分应用程序

    给定某个函数 f x1 x2 x3 xN 在多个地方部分应用它通常很有用 例如 对于 N 3 我们可以定义 g x f 1 x 3 然而 Haskell 中的标准部分应用程序并不是这样工作的 它只允许我们通过修复函数的第一个参数来部分应用函
  • 当基本词以 I 开头时,如何命名接口?

    我想为 Items 创建一个界面 通常 我会通过在基本词中添加 I 前缀来命名接口 但在这种情况下 我的基本词已经以 I 开头 以下是我的一些想法 IItem 两个我 Iitem 情况不同 项目接口 跳过I前缀 写出Interface 什么
  • Java静态方法的优缺点

    我以前没有使用过很多静态方法 但最近我倾向于使用更多静态方法 例如 如果我想在类中设置一个布尔标志 或者访问一个类而不需要通过类传递实际对象 例如 public class MainLoop private static volatile
  • rabbitmq-erlang-client,使用 rebar 友好的 pkg,在开发环境上工作在 rebar 版本上失败

    我成功地将rabbitmq erlang client的rebar友好包用于一个简单的Hello World rebarized和OTP 兼容 应用程序 并且在开发环境中工作正常 我能够启动 erl 控制台并执行我的操作applicatio
  • MemberwiseClone 相当于现有对象吗?

    这里有很多关于 MemberwiseClone 的问题 但我找不到任何准确的内容 据我了解 MemberwiseClone 基本上只是复制对象的内存区域 将其转储到其他地方 然后将其称为该对象的新实例 显然非常快 对于大型对象来说 这是制作
  • 使用 .NET Core 3.1 sdk 时,有没有办法限制 .NET Core 项目仅生成 .dll 作为输出文件

    当我使用 NET Core 3 1 sdk 构建 NET Core 控制台应用程序时 它会生成 exe 和 dll 作为输出 当我使用 NET Core 2 1 时 它仅生成 dll 作为输出 有没有办法限制 NET Core 3 1 sd
  • 创建一个排除某些文件的补丁文件

    我想创建一个补丁文件 仅将某些文件从 dir2 修补到 dir1 两者都是同一项目的 git 存储库 但是 dir2 包含第一个版本的高度修改版本 我只想修补对某些文件所做的更改 dir2 还具有 dir1 没有的额外文件 主要是 dir1
  • 在 Ubuntu WSL2 上连接到本地主机的问题

    我在本地为 django 项目设置了 Apache2 服务器 并且运行得非常好 问题是 休息一天后我回到它并尝试连接到服务器 但不知何故我无法连接到它 即使在检查 apache 服务是否正在运行并重新加载配置以确保确定之后也是如此 我无法从
  • 在 Firefox 或我的代理中禁用 websocket

    我已将 Firefox 配置为使用我的 http 和 https 代理 是的 我自己编写代理代码 因此我可以完全控制代理 您可能知道 无法再通过 about config 在 Firefox 中禁用 WebSocket 我正在寻找一种轻量级
  • C# 参数中的键值对

    我正在寻找一种方法来实现以下功能 myFunction Key value Key2 value 我确信匿名类型的某些东西会非常简单 但我没有看到它 我能想到的唯一解决方案是params KeyValuePair
  • Angular 6 observables - 从 .subscribe() 函数中提取数据并在其他地方使用

    我用可观察到的东西把头撞在墙上 我能找到的几乎所有文档都是较旧的rxjs句法 我有一个可观察的 API 调用 我在其他地方调用它并订阅它 尝试用此数据填充表GET要求 如果我简单地console log my getData函数 它记录订阅
  • 构造函数与类 {proguard] 不匹配

    我在我的应用程序中启用 proguard 每当我构建应用程序时 我都会收到以下错误 Constructor not matched for class com acs nomad d b e 根据我的映射文件 它所指的类如下 package
  • Android - 条码片段结果不显示

    解决了 应用程序工作正常 不会崩溃 但应该将 resultView 文本从 Hasil Scan 更新为扫描结果 但事实并非如此 问题是扫描后文本视图 结果视图 未更新 我使用 DM77 Zxing 条码扫描仪 这是我到目前为止所做的代码
  • 在 Swift 中传递并打印枚举中的所有情况

    考虑这个简单的枚举 enum myEnum String case abc ABC case xyz XYZ 我想编写一个可以打印枚举中所有情况的函数 喜欢 printEnumCases myEnum 预期结果 ABC XYZ 注意 我可以
  • 尝试 UNINSTALL_SHORTCUT 但快捷方式不会消失

    我创建了一个测试活动 它在 Android 主屏幕上安装了它自己的快捷方式 当您单击按钮时 活动应该删除它刚刚创建的相同快捷方式 但是 我似乎没有做任何事情来删除快捷方式 下面是 Java 代码 ShortcutTest java impo