Виджет Android запускает приложение и обнаруживает, что приложение не найдено

Мне нужен простой домашний виджет для запуска внешнего приложения (например, WhatsApp).

В моем MainActivity расширяет AppWidgetProvider (onUpdate) я использую этот код для создания ожидающего намерения и отлично работает, если приложение установлено.

Intent intent = new Intent();
ComponentName cn = new ComponentName("com.whatsapp", "com.whatsapp.Main");
intent.setComponent(cn);

PendingIntent pending = PendingIntent.getActivity(context, 0, intent, 0);

RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.activity_main);
views.setOnClickPendingIntent(R.id.imageView, pending);

appWidgetManager.updateAppWidget(currentWidgetId, views);

В разделе (onReceive) я использую этот код для определения того, установлено ли приложение

 PackageManager pm = context.getPackageManager();

        List<ApplicationInfo> list = pm.getInstalledApplications(0);

        for (int aa = 0; aa < list.size(); aa++) {         
            if(list.get(aa).packageName.equals("com.whatsapp")){  
                 //app istalled
                noapp = 0;
            }
            else{
                //app not istalled
                noapp1 = 1;         
            }
        }         
    if(noapp1==1){
    Toast.makeText(context, "Whatsapp not installed", Toast.LENGTH_SHORT).show();
  }

Моя проблема: этот код определяет, не установлено ли приложение, и отображает сообщение Toast, но только при первом размещении виджета в доме. Мне нужно отображать сообщение каждый раз, когда прикасается к изображению, если приложение не установлено. Пожалуйста помоги!

Каракури, я пытаюсь применить ваше предложение. Это мой код в основном действии для присоединения намерения к imageView:

public class MainActivity extends AppWidgetProvider{

public void onUpdate(Context context, AppWidgetManager appWidgetManager,
        int[] appWidgetIds) {
    for(int i=0; i<appWidgetIds.length; i++){
        int currentWidgetId = appWidgetIds[i];

        Intent intent = new Intent(LaunchExternalAppReceiver.ACTION);
        PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);

        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.activity_main);
        views.setOnClickPendingIntent(R.id.imageView, pendingIntent); 
        // Tell the AppWidgetManager to perform an update on the current App Widget
        appWidgetManager.updateAppWidget(currentWidgetId, views);

    }      
  }   
}

И это новый класс с BroadcastReceiver (я добавил свой простой код, чтобы проверить, установлено ли приложение, просто для теста):

public class LaunchExternalAppReceiver extends BroadcastReceiver {
public static final String ACTION = "control";

@Override
public void onReceive(Context context, Intent intent) {

    PackageManager pm = context.getPackageManager();

    List<ApplicationInfo> list = pm.getInstalledApplications(0);

    for (int aa = 0; aa < list.size(); aa++) {  

        if(list.get(aa).packageName.equals("com.whatsapp")){  
            //app istalled

        }
        else{
            //app not istalled             
            Toast.makeText(context, "Whatsapp not installed", Toast.LENGTH_SHORT).show();
        }
    }             
  }
}

Это мой манифест:

 <uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="19" /><application
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name" >
    <receiver android:name=".MainActivity" >
        <intent-filter>
            <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
        </intent-filter>

        <meta-data
            android:name="android.appwidget.provider"
            android:resource="@xml/mywidget" />
    </receiver>
    <receiver android:name=".LaunchExternalAppReceiver" >
        <intent-filter>
            <action android:name="control" >
            </action>
        </intent-filter>
    </receiver>
</application>

Спасибо большое за вашу помощь.


person Daniel    schedule 08.08.2015    source источник


Ответы (2)


Попросите ImageView отправить широковещательную рассылку получателю в вашем приложении (используя PendingIntent.getBroadcast()). В этом приемнике вы можете проверить, установлено ли внешнее приложение, и запустить его оттуда.

ИЗМЕНИТЬ

Создайте новый BroadcastReceiver.

public class LaunchExternalAppReceiver extends BroadcastRecevier {
    public static final String ACTION = "some-unique-string-here";

    @Override
    public void onReceive(Context context, Intent intent) {
        // check if the external app is installed and launch it
        PackageManager pm = context.getPackageManager();
        try {
            pm.getApplicationInfo("com.whatsapp", 0); // throws if not found
            Intent intent = pm.getLaunchIntentForPackage("com.whatsapp");
            if (intent != null) {
                context.startActivity(intent);
            }
        } catch (NameNotFoundException e) {
            // package not found, you can show the Toast here
        }
    }
}

Добавьте его в свой AndroidManifest. Убедитесь, что действие фильтра намерений соответствует ДЕЙСТВИЮ выше.

<receiver android:name=".LaunchExternalAppReceiver">
    <intent-filter>
        <action android:name="some-unique-string-here">
    </intent-filter>
</receiver>

Заставьте свой ImageView отправлять широковещательную рассылку с помощью этого действия вместо того, чтобы пытаться запустить внешнее приложение.

Intent intent = new Intent(LaunchExternalAppReceiver.ACTION);
PendingIntent pendingIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
remoteViews.setOnClickPendingIntent(R.id.imageView, pendingIntent);
person Karakuri    schedule 08.08.2015
comment
Спасибо Каракури. Я пробую это в своем разделе onUpdate.... if (PendingIntent.getBroadcast (контекст, 0, намерение, 0)!= null) {что-то делать}, но всплывающее сообщение все еще появляется, когда виджет открыт, а не по щелчку. Можете ли вы объяснить больше, пожалуйста. - person Daniel; 09.08.2015
comment
Заставьте imageView отправлять широковещательное намерение вместо намерения, которое запускает другое приложение. - person Karakuri; 09.08.2015
comment
Это выше моего знания кода. Можете ли вы показать мне код, чтобы сделать это? Мой код для привязки намерения к imageView находится в верхней части этого поста. - person Daniel; 09.08.2015
comment
@Daniel Смотрите мои правки. Я думаю, ты делаешь вещи сложнее, чем они есть на самом деле. Кроме того, я не рекомендую запускать компоненты другого приложения по имени; вы никогда не знаете, когда они могут решить обновить свое приложение и изменить название своих классов. - person Karakuri; 09.08.2015
comment
Спасибо. У меня все еще есть проблемы. Я поместил свой тестовый код выше. Я действительно ценю твою помощь. - person Daniel; 10.08.2015
comment
Каракури Я поместил свой код в ваш Edit, но исчез. Почему? Как я могу опубликовать это? - person Daniel; 10.08.2015
comment
@Daniel Отредактируйте свой собственный пост. - person Karakuri; 10.08.2015
comment
Готовый. Извините за ошибку. - person Daniel; 10.08.2015
comment
На этом этапе вам придется попытаться сузить, какая часть не работает. Добавьте несколько операторов журнала в разных местах (onUpdate поставщика AppWidget, onReceive широковещательного приемника и т. д.) и посмотрите, что произойдет. - person Karakuri; 10.08.2015
comment
Привет, Каракури. Я нашел работающее альтернативное решение, но мне нужно решить небольшую проблему. Можешь мне помочь? - person Daniel; 17.08.2015

Я нашел альтернативное решение. Работа приветствуется, но есть раздражающая маленькая проблема. Я прикрепляю намерение к imageView в своей основной деятельности, чтобы запустить новый класс «управление» в этом классе. Я проверяю, установлено ли приложение, и запускаю ее, или отправляю сообщение и предлагаю кнопку загрузки. Проблема в том, что... если приложение установлено, класс управления запускает ее, но на секунду появляется экран активности (управления) перед открытием приложения. Очень назойливый. Кто-нибудь может помочь мне сделать это окончательное исправление? Спасибо.

В onUpdate (основное действие):

    Intent controlIntent = new Intent(context, Control.class);          
    PendingIntent pendingc1 = PendingIntent.getActivity(context, 0, controlIntent, 0);
    RemoteViews views1 = new RemoteViews(context.getPackageName(), R.layout.activity_main);
    views1.setOnClickPendingIntent(R.id.imageView, pendingc1);
    appWidgetManager.updateAppWidget(currentWidgetId, views1); 

Мой новый класс (управление):

public class Control extends Activity {
private TextView testo;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    PackageManager pm = this.getPackageManager();

    List<ApplicationInfo> list = pm.getInstalledApplications(0);

    for (int aa = 0; aa < list.size(); aa++) {

        if (list.get(aa).packageName.equals("com.whatsapp")) {
            // app istalled

            Intent launchIntent = getPackageManager()
                    .getLaunchIntentForPackage("com.whatsapp");
            startActivity(launchIntent);
            Control.this.finish();

        } else {
            setContentView(R.layout.control);
            // app not istalled
            testo = (TextView) findViewById(R.id.message);
            String text = "WhatsApp is Not Installed\nPlease Download Whatsapp from Play Store";
            testo.setText(text);

            Button button = (Button) findViewById(R.id.exit);
            button.setOnClickListener(new View.OnClickListener() {

                public void onClick(View v) {
                    Control.this.finish();
                }
            });

            Button button2 = (Button) findViewById(R.id.download);
            button2.setOnClickListener(new View.OnClickListener() {

                public void onClick(View v) {
                    startActivity(new Intent(Intent.ACTION_VIEW, Uri
                            .parse("market://details?id=" + "com.whatsapp")));
                    Control.this.finish();
                }
            });

        }
    }
  }
}
person Daniel    schedule 17.08.2015