这是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>
我几乎肯定有一些权限问题,虽然我在互联网上看到其他帖子表明这应该是可能的.
任何意见是极大的赞赏.
谢谢.
解决方法
这个答案发布于2014年,当时描述的方法依赖于大多数Android设备中存在的功能.但是,如Adrian-Costin Țundrea所述,这个功能was removed几年前来自Launcher3,它是Google Now Launcher所基于的AOSP启动器1.提交消息说:
Removing support due to its flacky design. Removing a shortcut
causes a full reload. Also we do not have any concept of owner,so
any app can remove any shortcut.
截至2017年3月,该发射器也支持“谷歌搜索启动器服务”,这意味着制造商可以将某个谷歌库集成到他们自己的自定义发射器中,而不是依靠谷歌提供的标准化发射器.
考虑到每个制造商可以自由地以他们想要的方式实现他们的启动器,并假设其中一些基于Launcher3,很难分辨下面的方法将使用哪些设备,因为Launcher3甚至可以在某些Android 4.1设备上运行,这是oldest devices still in use之间的.
问候!
我刚刚处理了同样的问题,并希望在成功解决之后分享我的经验. tl; dr – 跳到下面的“结论”.
一些背景:
在处理应用程序的“下一版本”时,需要更改默认入口点(即重命名“主要活动”).这是不赞成的,因为从旧版本升级的用户仍然会使用旧的快捷方式,指向错误的位置.为了尽可能避免出现问题,在他们不知情的第一次发射时,旧的捷径将被换成新的捷径.
第1步:设置新的入口点
这是最简单的部分.要声明一个入口点,唯一要做的就是放下以下< action ...>在Manifest中的相应活动声明中标记:
<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>
在某种意义上,入口点默认是什么,是启动器快捷方式指向它.这就是为什么开发人员通常也会在< intent-filter>中包含它:
<category android:name="android.intent.category.LAUNCHER"/>
应该注意的是,在< intent-filter>中具有此功能的每个活动都是如此.将在您的应用程序抽屉中创建一个项目 – 这就是为什么在大多数情况下,您只需要1个实例.
第2步:弄清楚旧捷径如何工作
有了root设备,我可以访问存储启动器/主屏幕/桌面项目的数据库表(see image of what the SQLite entries looks like),它位于:
/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中解释.
第3步:确定快捷方式卸载程序的期望
UninstallShortcutReceiver.java中的第38-42行告诉我们:
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) { ... }
意味着“卸载意图”必须同时具有Intent.EXTRA_SHORTCUT_INTENT和Intent.EXTRA_SHORTCUT_NAME,否则它甚至不会考虑执行.
第4步:找到正确的语法
这是一个试错的案例,结局很快.
尝试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);
结果:图标未删除.
0x10200000实际上是两个参数的总和,如here所述.
尝试2:使用来自viralpatel的as-is代码
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);
结果:图标未删除.
尝试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);
结果:图标已删除!!
结论
>确保“Icon Uninstaller”意图使用与用于创建要删除的图标完全相同的URI,方法是存储用于创建它的URI,或者从launcher.db获取它.
>等待大约2-3秒,以显示“已删除图标”的吐司.
来源
1)This guide at viralpatel.net
2)Google’s implementation of UninstallShortcutReceiver.java
3)This thread at xdadevelopers
附:
为了模拟和调试Google Play更新(保留旧的快捷方式),我执行了以下操作:
>从商店安装旧版本的应用程序 – 带有“旧快捷方式”的图标自动放在我的屏幕上.
>使用Total Commander备份我的launcher.db.
>通过我的IDE安装新版本(您也可以使用.apk) – “旧快捷方式”现在已经消失.
>打开Total Commander并将其最小化(以便在“ALT-TAB”菜单中提供快捷方式).
>转到设备设置>>应用>> ALL,发现我的发射器(对我来说,因为我在CM11上它是“投石机”)并且Force停止了它.
> ALT-TAB进入Total Commander并恢复数据库.
>单击硬件“主页”按钮以重新启动启动器.
>中提琴!旧的快捷方式现已恢复.
注意1:回顾一下,使用从数据库获取的URI手动创建旧快捷方式可能更容易,而不是通过所有备份和强制停止测试.
注意2:我没有尝试使用此方法删除属于其他应用程序的图标,但它可能只是疯狂到可以工作.