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

Tim*_*mmm 19 android widget launcher android-4.0-ice-cream-sandwich

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

崩溃是因为股票启动器appWidgetManager.bindAppWidgetId(appWidgetId, componentName);用来添加小部件,显然只有系统应用程序才有权这样做.

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

Fuz*_*gic 12

Timmmm,

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

编辑:Widget绑定过程的额外背景

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

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

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

行动过程(EDITED)

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

<uses-permission android:name="android.permission.BIND_APPWIDGET" />
Run Code Online (Sandbox Code Playgroud)

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

AppWidgetHost myHost = new AppWidgetHost(context, SOME_NUMERICAL_CONSTANT_AS_AN_ID);
Run Code Online (Sandbox Code Playgroud)

现在,获取您的ID:

myHost.allocateAppWidgetId()
Run Code Online (Sandbox Code Playgroud)

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

AppWidgetProviderInfo withWidgetInfo 
        = AppWidgetManager.getInstance().getAppWidgetInfo(forWidgetId);
AppWidgetHostView hostView 
        = myWidgetHost.createView(myContext, forWidgetId, withWidgetInfo);
hostView.setAppWidget(forWidgetId, withWidgetInfo);
Run Code Online (Sandbox Code Playgroud)

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

myViewGroup.addView(hostView);
Run Code Online (Sandbox Code Playgroud)

当然,你总是要考虑放置它的位置和方法等.另外,AppWidgetHost在开始添加小部件之前,你必须确保你正在听.

myHost.startListening()

总结一下

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

编辑:最终澄清

ICS Launcher也是这样做的.在appWidgetManager他们使用的是只是一个包装外壳AppWidgetHost,并给了电话AppWidgetManager.我忘了在Android Development Central网站上解释的很少.

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

FuzzicalLogic

  • @Fuzzical Logic您的方法只适用于旧的AppWidgetPickActivity,而不是ICS.因为AppWidgetPickActivity也使用mAppWidgetManager.bindAppWidgetId(mAppWidgetId,intent.getComponent()); 它驻留在系统应用程序:设置中,而设置有权绑定appwidget. (2认同)
  • @herbertD:没有违法行为,但这正是我所说的."BIND_APPWIDGET"是系统权限,仅供系统使用.如果设置应用程序作为ROM的一部分安装,则允许设置.是的,我的方法是"老方法",但对象仍然存在于ICS中,它适用于使用4.0的启动器.事实上,这就是OP发布这个帖子的原因......因为BIND_APPWIDGET只是一个**系统**权限****.我的解决方案不适合您,因为您使用**自定义**小部件选择器.如果您想找到解决方案,请更改您的选择器或制作新问题. (2认同)

Tim*_*mmm 8

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

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

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

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

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