0
1

More than 3 years have passed since last update.

【ぶっちゃけAndroidアプリ開発】Widgetをクリックしてもブロードキャストされない

Last updated at Posted at 2019-12-18

初めてAndroidのWidgetアプリを作る事になり、ネット上のサンプルアプリを動かそうとしたら、ウィジェットをクリックした時にブロードキャストが受け取れない(発生しない)という状況になり、ハマりました。
同じ悩みを抱える人のために取り急ぎ解決方法を記載しておきます。

結果的には、SDKバージョンの仕様変更によるものでした。
わたしのAndroid Studioは、2019年12月時点で最新バージョンを導入しています。

<前提>
・Android Studio 3.5.3
・compileSdkVersion 29
・buildToolsVersion "29.0.2"
・minSdkVersion 15
・targetSdkVersion 29

1.サンプルコード

以下の二つを実装してみましたが、うまく行きません。
・クリックするとToast表示するアプリ
https://qiita.com/s-yamda/items/cba2c6c134303f29d4ab
・クリックするとおみくじが引けるアプリ
http://fourtec.net/pc-blogs/2794

マニフェストファイルは以下の通り。
サンプル通り、receiverのintent-filterタグに、actionを挿入しています。

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.testwidget">

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <receiver android:name=".NewAppWidget">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_UPDATE" />
                <action android:name="CLICK_WIDGET"/>
            </intent-filter>

            <meta-data
                android:name="android.appwidget.provider"
                android:resource="@xml/new_app_widget_info" />
        </receiver>

        <activity android:name=".NewAppWidgetConfigureActivity">
            <intent-filter>
                <action android:name="android.appwidget.action.APPWIDGET_CONFIGURE" />
            </intent-filter>
        </activity>
    </application>

</manifest>

AppWidgetProviderウィジェット実装ファイル。
ウィジェットの文字をクリックするとブロードキャストが発生し、onReceiveに飛んでToast出力するというだけのもの。

NewAppWidget.java
package com.example.testwidget;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

/**
 * Implementation of App Widget functionality.
 * App Widget Configuration implemented in {@link NewAppWidgetConfigureActivity NewAppWidgetConfigureActivity}
 */
public class NewAppWidget extends AppWidgetProvider {

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {

        CharSequence widgetText = NewAppWidgetConfigureActivity.loadTitlePref(context, appWidgetId);
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

        //クリックを識別する文字列
        Intent intent = new Intent("CLICK_WIDGET");
        PendingIntent pIntent = PendingIntent.getBroadcast(context, appWidgetId, intent , 0);

        //ウィジェットテキストの変更
        views.setTextViewText(R.id.appwidget_text,"CLICK!");
        //ウィジェットを押したときにインテントが発行される
        views.setOnClickPendingIntent(R.id.appwidget_text,pIntent);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        // When the user deletes the widget, delete the preference associated with it.
        for (int appWidgetId : appWidgetIds) {
            NewAppWidgetConfigureActivity.deleteTitlePref(context, appWidgetId);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    @Override
    public void onReceive(Context context, Intent intent){
        super.onReceive(context,intent);
        //Manifestに登録されたActionと発行したインテントが同じ場合に実行される
        if (intent.getAction().equals("CLICK_WIDGET")) {
            Toast.makeText(context, "クリックされました!", Toast.LENGTH_SHORT).show();
        }

    }
}

がしかし、いくらウィジェットを押してもToastは出力されません。
logcat仕掛けてみると、onReceiveのイベントすら発生していない模様です。

2.解決方法

以下のQAサイトに解決方法が記載されていました。
どうやらAndroid Oreo(API26)以降で仕様が変わり、intentにactionをセットする方法を変更しなければならないようです。
https://teratail.com/questions/225130

「// 変更」とコメントしてある2行を変更しました

NewAppWidget.java
package com.example.testwidget;

import android.app.PendingIntent;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProvider;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.RemoteViews;
import android.widget.Toast;

/**
 * Implementation of App Widget functionality.
 * App Widget Configuration implemented in {@link NewAppWidgetConfigureActivity NewAppWidgetConfigureActivity}
 */
public class NewAppWidget extends AppWidgetProvider {

    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager,
                                int appWidgetId) {

        CharSequence widgetText = NewAppWidgetConfigureActivity.loadTitlePref(context, appWidgetId);
        // Construct the RemoteViews object
        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);

        //クリックを識別する文字列
        Intent intent = new Intent(context, NewAppWidget.class); // 変更
        intent.setAction("CLICK_WIDGET"); // 変更
        PendingIntent pIntent = PendingIntent.getBroadcast(context, appWidgetId, intent , 0);

        //ウィジェットテキストの変更
        views.setTextViewText(R.id.appwidget_text,"CLICK!");
        //ウィジェットを押したときにインテントが発行される
        views.setOnClickPendingIntent(R.id.appwidget_text,pIntent);

        // Instruct the widget manager to update the widget
        appWidgetManager.updateAppWidget(appWidgetId, views);
    }

    @Override
    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
        // There may be multiple widgets active, so update all of them
        for (int appWidgetId : appWidgetIds) {
            updateAppWidget(context, appWidgetManager, appWidgetId);
        }
    }

    @Override
    public void onDeleted(Context context, int[] appWidgetIds) {
        // When the user deletes the widget, delete the preference associated with it.
        for (int appWidgetId : appWidgetIds) {
            NewAppWidgetConfigureActivity.deleteTitlePref(context, appWidgetId);
        }
    }

    @Override
    public void onEnabled(Context context) {
        // Enter relevant functionality for when the first widget is created
    }

    @Override
    public void onDisabled(Context context) {
        // Enter relevant functionality for when the last widget is disabled
    }

    @Override
    public void onReceive(Context context, Intent intent){
        super.onReceive(context,intent);
        //Manifestに登録されたActionと発行したインテントが同じ場合に実行される
        if (intent.getAction().equals("CLICK_WIDGET")) {
            Toast.makeText(context, "クリックされました!", Toast.LENGTH_SHORT).show();
        }

    }
}

これで無事にToast出力されるようになりました。
コードを修正したくない場合は、targetSdkVersionをバージョン25以下に下げてもうまく行きます。

0
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
1