Android - 将AppWidgets添加到一个Activity

9

我的初始目标是将Google搜索小部件添加到活动的线性布局中。我需要像在启动器中一样添加并工作,这就是为什么我需要能够添加小部件的原因。


我想在不必启动小部件选择器活动的情况下向我的活动添加小部件。我尝试过:

1. 直接指定整数ID(我总是得到膨胀错误)

2. 像这样获取ID:

  ComponentName cn = new ComponentName(getBaseContext(), "com.android.quicksearchbox.SearchWidgetProvider");
  int[] ids = AppWidgetManager.getInstance(getApplicationContext()).getAppWidgetIds (cn);

这个数组总是为空。

这些都不起作用。

接下来,我有这段代码,用于使用ID(如果我从小部件选择器活动中获取ID,则有效):

    AppWidgetProviderInfo withWidgetInfo = AppWidgetManager.getInstance(getApplicationContext()).getAppWidgetInfo(appWidgetId);
    AppWidgetHostView hostView = myWidgetHost.createView(getBaseContext(), appWidgetId, withWidgetInfo);
    hostView.setAppWidget(appWidgetId, withWidgetInfo);
    LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
    ll.addView(hostView);

我该怎么做呢?谢谢!
2个回答

19

试试这个:

// APPWIDGET_HOST_ID is any number you like
appWidgetManager = AppWidgetManager.getInstance(this);
appWidgetHost = new AppWidgetHost(this, APPWIDGET_HOST_ID);
AppWidgetProviderInfo newAppWidgetProviderInfo = new AppWidgetProviderInfo();

// Get an id
int appWidgetId = appWidgetHost.allocateAppWidgetId();

// Get the list of installed widgets
List<AppWidgetProviderInfo> appWidgetInfos = new ArrayList<AppWidgetProviderInfo>();
appWidgetInfos = appWidgetManager.getInstalledProviders();

for(int j = 0; j < appWidgetInfos.size(); j++)
{
    if (appWidgetInfos.get(j).provider.getPackageName().equals("com.android.quicksearchbox") && appWidgetInfos.get(j).provider.getClassName().equals("com.android.quicksearchbox.SearchWidgetProvider"))
    {
        // Get the full info of the required widget
        newAppWidgetProviderInfo = appWidgetInfos.get(j);
        break;
    }
 }

// Create Widget
AppWidgetHostView hostView = appWidgetHost.createView(this, appWidgetId, newAppWidgetProviderInfo);
hostView.setAppWidget(appWidgetId, newAppWidgetProviderInfo);

// Add it to your layout
LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
ll.addView(hostView);

编辑:

为了绑定小部件ID,即使小部件更新并响应用户交互,请参考此处的解决方案:Widgets don't respond when re-added through code


1
以上代码仅显示小部件,但如果没有appWidgetManager.bindAppWidgetId(),它将无法响应用户的点击。 - herbertD
但是 appWidgetManager.bindAppWidgetId(); 只能由系统应用程序执行,对吗?即使我正在寻找解决方法,你能帮忙吗? - Kamran Ahmed
如果有人仍然想知道如何在没有系统权限的情况下绑定小部件ID,请参考此处的答案:https://dev59.com/u2bWa4cB1Zd3GeqPTBNI#44351320 - Kamran Ahmed
1
@KamranAhmed 如果我这样做(我试图将日历添加到我的屏幕上),我只能看到该小部件的容器,里面没有任何数据。而且它也无法点击,实际上它不会打开应用程序。有什么想法吗?谢谢 - joe
@KamranAhmed 我创建了一个数字时钟,使用Alarm Manager进行更新,如果我将其添加到主屏幕应用程序中,它可以正常工作......但是当我像你说的那样将这个数字时钟添加到我的主机上后,时钟就无法通过AlarmManager进行更新了... - Imran Khan Saifi
显示剩余5条评论

6

好的,我已经能够编写出可行的代码(除了它不应该那么容易地工作,详情如下所示)。

应该可以正常工作的代码是:

        //create ComponentName for accesing the widget provider
        ComponentName cn = new ComponentName("com.android.quicksearchbox", "com.android.quicksearchbox.SearchWidgetProvider");
        //ComponentName cn = new ComponentName("com.android.music", "com.android.music.MediaAppWidgetProvider");

        //get appWidgetManager instance
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getBaseContext());
        //get list of the providers - .getAppWidgetIds (cn) does seem to be unrelated to widget hosting and more related to widget development
        final List<AppWidgetProviderInfo> infos = appWidgetManager.getInstalledProviders();

        //get AppWidgetProviderInfo
        AppWidgetProviderInfo appWidgetInfo = null;
        //just in case you want to see all package and class names of installed widget providers, this code is useful
        for (final AppWidgetProviderInfo info : infos) {
            Log.v("AD3", info.provider.getPackageName() + " / "
                    + info.provider.getClassName());
        }
        //iterate through all infos, trying to find the desired one
        for (final AppWidgetProviderInfo info : infos) {
            if (info.provider.getClassName().equals(cn.getClassName()) && info.provider.getPackageName().equals(cn.getPackageName())) {
                //we found it
                appWidgetInfo = info;
                break;
            }
        }
        if (appWidgetInfo == null)
            return; //stop here

        //allocate the hosted widget id
        int appWidgetId = myWidgetHost.allocateAppWidgetId();

        //bind the id and the componentname - here's the problem!!!
        appWidgetManager.bindAppWidgetId(appWidgetId, cn); 

        //creat the host view
        AppWidgetHostView hostView = myWidgetHost.createView(getBaseContext(), appWidgetId, appWidgetInfo);
        //set the desired widget
        hostView.setAppWidget(appWidgetId, appWidgetInfo);

        //add the new host view to your activity's GUI
        LinearLayout ll = (LinearLayout) findViewById(R.id.ll);
        ll.addView(hostView);

问题出在"appWidgetManager.bindAppWidgetId(appWidgetId, cn);",需要在manifest中添加BIND_APPWIDGET权限才能运行。即使添加了该权限并将apk放到system/app文件夹中,它仍然无法正常工作(这并不会使其成为系统应用程序)。

关于这个问题,我在这里找到了以下答案:

这是故意不提供给应用程序的。如果你想添加小部件,你需要启动选择器UI来让用户选择小部件,然后它会处理绑定。小部件可以公开各种私人数据,因此不安全允许应用程序随意绑定它们而不经过用户明示地批准(通过选择UI)。

Dianne ... Android框架工程师

然而,我不确定,也许这意味着如果我们能用图像开发者的密钥签署apk,我们就可以实现所需的功能?但是,这超出了问题的主题。但如果你恰好能够解释如何有效地托管AppWidgets,请解释并让你的答案被我接受(市场上的启动器应用程序可以做到,所以一定是可能的)。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接