Отправка Intent из виджета в стороннее приложение (Android)

Поделюсь своим опытом, ведь не каждый разработчик сталкивается с разработкой абсолютно каждой фичи в Android.

Как то меня посетила идея прикрутить к своему приложению виджет. Но прикрутить его по хитрому — сделав его совершенно отдельной программой.

Для чего это нужно? Ну, предположим, что вы хотите продавать некоторые части (функционал) приложения отдельно. Будь то чат, виджет календаря, виджет погоды и т.д.

Как осуществить связь разрабатываемого отдельно виджета с основным приложением? На самом деле, не долго думая, в голову приходит элементарно простое решение — с помощью Intent-ов, Receiver-ов и общего Action.

Сейчас я покажу, как с минимальными затратами усилий подключить только что созданный виджет к своему приложению.

Создаём виджет через автоматический шаблон в Android Studio. Получаем что-то вроде такого:

public class SomeWidget extends AppWidgetProvider {

static void updateAppWidget(Context context, AppWidgetManager
appWidgetManager,int appWidgetId) {
RemoteViews views = new
RemoteViews(context.getPackageName(),
R.layout.some_widget);

appWidgetManager.updateAppWidget(appWidgetId, views);
    }

@Override
public void onUpdate(Context context, AppWidgetManager
appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}

@Override
public void onEnabled(Context context) {
}

@Override
public void onDisabled(Context context) {
}
}

Ничего удивительного в этом коде нет. Обычный шаблон.

Теперь нам надо сделать 3 вещи:

  1. Добавить элемент в layout файл нашего виджета (R.layout.some_widget)
  2. Присвоить этому элементу (не важно что это, кнопка, текстовое поле или рисунок) идентификатор
  3. Так как виджет является Receiver-ом, то нам надо придумать название Action и прописать его в манифесте в теге <intent-filter> (в шаблоне это уже сделано, но я советую сделать новый Action). Например: com.example.myApp.SOME_BUTTON_PRESSED

Далее, работаем с кодом. В качестве примера я добавил кнопку с id “button”.

public class SomeWidget extends AppWidgetProvider {

static void updateAppWidget(Context context, AppWidgetManager
appWidgetManager,int appWidgetId) {
RemoteViews views = new
RemoteViews(context.getPackageName(),
R.layout.some_widget);
        Intent intent = new Intent();
intent.setAction("com.example.myApp.SOME_BUTTON_PRESSED");

PendingIntent pendingIntent =
PendingIntent.getBroadcast(context,0, intent,
PendingIntent.FLAG_UPDATE_CURRENT);

views.setOnClickPendingIntent(R.id.button, pendingIntent);
        appWidgetManager.updateAppWidget(appWidgetId, views);
}

@Override
public void onUpdate(Context context, AppWidgetManager
appWidgetManager, int[] appWidgetIds) {
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}

@Override
public void onEnabled(Context context) {
}

@Override
public void onDisabled(Context context) {
}
}

Мы сделали следующее:

  1. Создали Intent и присвоили ему наш Action
  2. Обернули наш Intent в PendingIntent с флагом FLAG_UPDATE_CURRENT
  3. Указали, что при клике на элементе “button” в виджете будет запущено PendingIntent

Далее, ниже мы пишем метод OnReceive (ведь у нас всё же Receiver).

@Override
public void onReceive(Context context, Intent intent) {
super.onReceive(context, intent);
if (intent.getAction()
.equals("com.example.myApp.SOME_BUTTON_PRESSED"))
{
Intent toMainApp = new Intent();
           toMainApp.setAction                           
("com.example.anotherApp.SOME_BUTTON_PRESSED");

context.sendBroadcast(toMainApp);
}
}

Здесь мы создаём новый Intent и задаём ему Action, который будет отлавливаться Receiver-ом на стороне другого приложения и отправляем его.

После этого остаётся лишь создать в основном приложении Receiver, который на вход принимает Action: com.example.anotherApp.SOME_BUTTON_PRESSED и обработать его.

Вот и всё.

С наилучшими пожеланиями.