Вопрос по android, manifest, android-activity, android-intent, shortcut – Попытка UNINSTALL_SHORTCUT, но ярлык не исчезнет

8

Я создал тестовое задание, которое устанавливает ярлык на главном экране 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> 

Я почти уверен, что есть какая-то проблема с разрешениями, хотя я видел другие посты в Интернете, которые указывают, что это возможно.

Любые советы высоко ценится

Благодарность

Ваш Ответ

5   ответов
20
DEPRECATED; УДЕРЖИВАЙТЕ ТОЛЬКО ДЛЯ ИСТОРИЧЕСКИХ ЦЕЛЕЙ

когда описанный метод основывался на функциональности, существующей в большинстве устройств Android. Тем не менее, как упоминалось Адриан-Костин Шундреа, эта функциональностьбыл удале Пару лет назад из Launcher3, запускающего AOSP, на котором основан Google Now Launcher1. Сообщение коммита говорит:

Снятие поддержки из-за своего шикарного дизайна. Удаление ярлыка вызывает полную перезагрузку. Также у нас нет никакой концепции владельца, поэтому любое приложение может удалить любой ярлык.

По состоянию на март 2017 года этот лаунчер тоже постепенно сокращается в пользу «Служб Google Search Launcher», что означает, что производители могут интегрировать определенную библиотеку Google в свои собственные программы запуска вместо того, чтобы полагаться на стандартизированный модуль запуска Googl

Учитывая, что каждый производитель может свободно внедрять свои средства запуска, в зависимости от того, что они хотят, и, предполагая, что некоторые из них основаны на Launcher3, трудно сказать, на каких устройствах будет работать метод, описанный ниже, так как Launcher3 был запущен даже на некоторых Android 4.1 устройства, которые входят в число самые старые устройства все еще используются.

Приветствую

Я только что столкнулся с той же самой проблемой и хотел бы поделиться своим опытом после успешного ее решения.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>

Что делает точку входадефол в некотором смысле это означает, что ярлык на панели запуска указывает на это. Вот почему разработчики обычно также включают это в<intent-filter>:

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

Следует отметить, что каждое действие, которое имеет это в своем<intent-filter> вол создайте элемент в ящике приложения - вот почему в большинстве случаев вам нужен только один экземпляр.

Шаг 2: выяснить, как работает старый ярлык

Имея рутированное устройство, я мог получить доступ к таблице базы данных, в которой хранятся элементы запуска / рабочего стола / рабочего стола (см. изображение того, как выглядят записи SQLite) находится в:

/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. Выяснение того, что ожидает Деинсталлятор ярлыко

Линии 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) { ... }

Имеется ввиду, что «намерение удаления» должно иметьи то и друго 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 на самом деле сумма двух аргументов, как объясненоВо.

Попытка 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);

Результат Значок не удален.

Попытка 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);

Результат Значок удален !!

В заключени Убедитесь, что ваше намерение «Удаление значков» использует точно такой же URI, который использовался для создания значка, который вы пытаетесь удалить, либо сохраняя URI, использованный для его создания, либо получая его изlauncher.db. Подождите около 2-3 секунд, чтобы появился тост «Значок удален». Источники

1) Это руководство на viralpatel.net

2) Google реализует UninstallShortcutReceiver.java

3) Эта тема на xdadevelopers

Приписка

Для того, чтобы смоделировать и отладить обновление Google Play (которое сохраняет старый ярлык), я сделал следующее:

Установил старую версию приложения из магазина - на моем экране автоматически появилась иконка со «старым ярлыком». Сделайте резервную копию моего файла launcher.db с помощью Total Commander. Установил новую версию через мою IDE (вы также можете использовать .apk для этого) - теперь «старый ярлык» пропал. Открыл Total Commander и свернул его (чтобы ярлык был доступен в меню «ALT-TAB»). Зашел в Настройки устройства >> Приложения >> ВСЕ, нашел мой лаунчер (для меня это был "Требушет", так как я на CM11) и Сила остановилась Это ALT-TAB в Total Commander и восстановил БД. Нажмите аппаратную кнопку «Домой», чтобы перезапустить модуль запуска.Viola! Старый ярлык был восстановлен.

Примечание 1: В ретроспективе было бы проще создать старый ярлык вручную, используя URI, полученный из базы данных, вместо того, чтобы выполнять все операции резервного копирования и принудительного останова.

Примечание2: я не пытался удалить значки, принадлежащие другим приложениям, используя этот метод, но он может быть достаточно сумасшедшим, чтобы работать.

@ Dev-iL Я модифицирую Launcher3. Как я могу получить список ярлыков из панели запуска? rupesh
@ Pradip - Я думаю, вы могли бы просто догадаться, так как на самом деле очень мало комбинаций (IIRC). Просто загляните в launcher.db с телефона с более чем 60 приложениями, чтобы почувствовать это. Я только что проверил launcher.db на моем телефоне ивслаги @ на самом деле 0x10200000. Если я придумаю что-то еще, я дам вам знать:) Dev-iL
Попытка 3: «Brute Force» работал для удаления ярлыка другого приложения. Абсолютно круто, я не могу тебя отблагодарить. cprcrack
Попытка 3 работает. Но только на эмуляторе или рутированном телефоне. Как получитьlaunchFlags в рутированном телефоне? Есть идеи Pradip Kharbuja
3

Попробуй использоват

public void removeShortcut(Context context) {
        Intent intent = new Intent();

        intent.putExtra(Intent.EXTRA_SHORTCUT_NAME, "ShortcutTest");

        try {
            Intent shortcutIntent = Intent.parseUri(shortcutUri, 0);
            intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent);
        } catch (URISyntaxException e) {
        }
        intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
        context.sendBroadcast(intent);
    }

Примечание: вам не нужно сохранятьshortcutUri чтобы убрать ярлык. Вместо этого вы можете использовать

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();
try {
    intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
            Intent.parseUri(shortcutIntent.toUri(0), 0));
} catch (URISyntaxException e) {
    e.printStackTrace();
}
...
intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");
context.sendBroadcast(intent);

Если ты хочешь использоватьintent.putExtra(Intent.EXTRA_SHORTCUT_INTENT, shortcutIntent); вместо тог

intent.putExtra(Intent.EXTRA_SHORTCUT_INTENT,
                Intent.parseUri(shortcutIntent.toUri(0), 0));

тогда вам нужно установить действие дляshortcutIntent каждый раз, то есть при установке, а также при удалении, например,Intent shortcutIntent = new Intent(Intent.ACTION_MAIN);

shortcutUri <--- что это Yousha Aleayoub
к сожалению, в Marshmallow больше не работает, см. также Stackoverflow.com / а / 33731620/1545993 Taifun
0

стеке, но решение было очень простым. В вашем коде есть опечатка: вам нужно использовать com.android.launcher. Действие .UNINSTALL_SHORTCUT (в отличие от разрешения, как в Манифесте)

intent.setAction("com.android.launcher.action.UNINSTALL_SHORTCUT");

Редактировать: ответ исправлен

ты должно быть шутиш Shivansh
4

Вам нужно SetAction дляshortcutIntent нравится

shortcutIntent.setAction(Intent.ACTION_MAIN);
Благодарность! ты спас мне жизнь здесь DallaRosa
10

советуют делать это до Зефира. В Android 6.0 (с Launcher v3) Google удалил UninstallShortcutReceiver из-за проблем с безопасностью (возможно, потому что это стало очевиднымВо). Так что не ожидайте, что он будет работать с Android 6.0. Надеемся, что в будущем выпуске он будет читаться в той или иной форме.

PS: Обычно это должен быть комментарий, но я не могу комментировать из-за репутации ...

Как я уже сказал ... Мне бы хотелось иметь возможность комментировать, но из-за (отсутствия) репутации я не смог. Но так как я считаю, что это улучшает ответ, я пошел вперед. Это не ответ наверняка, но ответ больше не относится к Android Marshmallow. Это добавляет значение этой теме ... Adrian-Costin Țundrea
Некоторые пользователи Android решили по-прежнему поддерживать деинсталляцию на Android 6.Samsung, например. Они запутывают все как обычно. JacksOnF1re
Это не дает ответа на вопрос. Чтобы критиковать или запросить разъяснения у автора, оставьте комментарий под его постом - вы всегда можете комментировать свои собственные посты, и как только у вас будет достаточно Репутации Вы будете в состоянии комментарий к любому посту. - Из обзора Am_I_Helpful

Похожие вопросы