在没有bindAppWidgetId()的情况下将窗口小部件添加到启动器页面

时间:2012-03-17 00:33:12

标签: android widget android-4.0-ice-cream-sandwich launcher

我正在尝试将库存ICS启动器变成一个独立的应用程序。我几乎就在那里 - 唯一不起作用的是搜索图标和将小部件放到屏幕上,这会导致崩溃。

崩溃是因为股票启动器使用appWidgetManager.bindAppWidgetId(appWidgetId, componentName);添加小部件,apparently only system apps have permission to do

所以我的问题是,非系统应用添加小部件并获得与库存ICS启动器相同的UI体验的正确方法是什么?

4 个答案:

答案 0 :(得分:12)

Timmmm,

您的问题是您正在寻找错误的对象。你无法真正控制AppWidgetManager。它不是你的工作,它是系统的。你可以做的是控制AppWidgetHost,它只需要几个语义。以下是基础知识。

编辑:窗口小部件绑定过程的额外背景

AppWidgetManager是一个在系统启动时运行的单例对象。这意味着每个启动器的每个实例都使用相同的AppWidgetManager。它们的区别在于它们的AppWidgetHost和它们目前持有的RemoteView。 AppWidgetManager基本上保留了所有活动主机及其持有的小部件的列表。 AppWidgetHost不是一个priveleged对象。也就是说,任何活动都可能只有一个主机。因此,如果他们愿意,整个应用程序可能只是Widgets。

实例化主机时,必须先向其添加视图。所以,基本上它是一个没有强制父母界限的子视图列表,除了你的Activity提供它。首先,您要求提供ID(通过myHost.allocateAppWidgetId())。然后使用Pick Widget活动/对话框。 Dialog返回WidgetInfo。当您要求主持人使用WidgetInfo和您要求的ID创建视图(通过createView)时,将检索视图。然后它会向小部件询问其RemoteView

最后,通过将View作为子项放在Activity中来绑定窗口小部件。这是通过保存所有小部件的ViewGroup的addView()方法完成的。

行动过程(已编辑)

首先,你必须确保在你的Android清单中有这个:

<uses-permission android:name="android.permission.BIND_APPWIDGET" />

接下来,你必须创建一个AppWidgetHost(我为我的启动器扩展自己的)。主持人的关键是通过AppWidgetManager保留对AppWidgetManager.getInstance();的引用。

AppWidgetHost myHost = new AppWidgetHost(context, SOME_NUMERICAL_CONSTANT_AS_AN_ID);

现在,获取您的ID:

myHost.allocateAppWidgetId()

下一步是通过您用于获取小部件信息的任何方法完成的。大多数情况下,它通过onActivityResult通过Intent返回。现在,您真正需要做的就是使用appInfo并创建视图。 WidgetId通常由pick小部件活动结果提供。

AppWidgetProviderInfo withWidgetInfo 
        = AppWidgetManager.getInstance().getAppWidgetInfo(forWidgetId);
AppWidgetHostView hostView 
        = myWidgetHost.createView(myContext, forWidgetId, withWidgetInfo);
hostView.setAppWidget(forWidgetId, withWidgetInfo);

现在,您只需将View作为子项绑定到要绑定它的任何内容。

myViewGroup.addView(hostView);

当然,您始终需要考虑在何处以及如何放置它等。另外,在开始添加小部件之前,您必须确保AppWidgetHost正在侦听。

myHost.startListening()

总结

Widget绑定过程涵盖了许多方法和步骤,但都是通过AppWidgetHost进行的。因为窗口小部件是在命名空间之外编码的,所以除了放置它们的位置以及如何调整视图大小之外,您没有任何控件。由于它们最终是在您的空间中运行但不受您控制的代码,因此AppWidgetManager充当中立调解员,而AppWidgetHost则代表您的应用的辅导员。一旦理解了这一点,您的任务就很简单。上述步骤是任何自定义启动器(包括我自己的启动器)所需的所有步骤。

编辑:最终澄清

ICS Launcher也是这样做的。他们使用的appWidgetManager只是一个包含AppWidgetHostAppWidgetManager调用的包装器。我忘了在Android Development Central网站上解释的很少。

希望这有帮助!如果您需要更多详细信息,请与我们联系。

FuzzicalLogic

答案 1 :(得分:8)

我现在知道明确的答案。在Android 4.0中,你不能这样做。我最终让我的用户选择了两次小部件,这很糟糕,但没有办法解决它。

在Android 4.1中他们解决了这个问题!

SDK应用现在可以托管小部件,而不必使用垃圾小部件选择器API!您可以查看Jellybean Launcher2源代码了解详细信息,但基本上,当您第一次尝试绑定窗口小部件时,Android会弹出一个对话框,说“您是否要允许此应用程序绑定窗口小部件”,然后用户可以决定是否允许。

我不确定他们为什么选择模态权限授予对话框,而不是他们用于其他所有内容的所有权限安装模型,但无论如何,它都有效!

现在我们只需等待4或5年,直到每个人都拥有Android 4.1或更高版本!

答案 2 :(得分:4)

我刚刚找到了关于如何向普通应用添加appwidgets的教程,这可能有所帮助:http://coderender.blogspot.com/2012/01/hosting-android-widgets-my.html

本教程仍然使用“AppWidget Picker”列表,因此它可能不适合您,因为ICS在应用程序抽屉内部有小部件选择器。

仍然值得一提,因为有关托管小部件的教程非常罕见:)

干杯,
Yuvi

答案 3 :(得分:2)

模糊逻辑,您的代码如下,

AppWidgetProviderInfo withWidgetInfo 
        = AppWidgetManager.getInstance().getAppWidgetInfo(forWidgetId);
AppWidgetHostView hostView 
        = myWidgetHost.createView(myContext, forWidgetId, withWidgetInfo);
hostView.setAppWidget(forWidgetId, withWidgetInfo);

如果没有bind_widget的权限,widgethost什么都没有,cus withwidgetinfo为null,widgethost什么都不创建。