【问题标题】:Adding widgets to a launcher page without bindAppWidgetId()在没有 bindAppWidgetId() 的情况下将小部件添加到启动器页面
【发布时间】:2012-04-02 12:31:30
【问题描述】:

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

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

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

【问题讨论】:

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


    【解决方案1】:

    模糊逻辑,下面是你的代码,

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

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

    【讨论】:

    • 对于 getAppWidgetInfo 要返回一个对象,forWidgetId 必须已经绑定:通过系统选择器选择小部件或调用 bindAppWidgetIdIfAllowed,或者如果返回 false,则仅使用 startActivityForResult(AppWidgetManager.ACTION_APPWIDGET_BIND)正确的参数(参见文档)。
    【解决方案2】:

    我现在知道了明确的答案。在 Android 4.0 中,您无法做到这一点。我最终让我的用户选择了两次小部件,这很糟糕,但没有办法绕过它。

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

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

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

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

    【讨论】:

      【解决方案3】:

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

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

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

      干杯,
      尤维

      【讨论】:

        【解决方案4】:

        提姆,

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

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

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

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

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

        行动过程(已编辑)

        首先,你必须确保你的 android manifest 中有这个:

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

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

        AppWidgetHost myHost = new AppWidgetHost(context, SOME_NUMERICAL_CONSTANT_AS_AN_ID);
        

        现在,获取您的 ID:

        myHost.allocateAppWidgetId()
        

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

        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 只是一个封装AppWidgetHost 和对AppWidgetManager 的调用。我忘记了在 Android Development Central 网站上对此的解释很少。

        希望这会有所帮助!如果您需要更多详细信息,请告诉我。

        模糊逻辑

        【讨论】:

        • 感谢您的回答,但不幸的是它似乎并没有解决我的问题: 1.我认为您使用 BIND_APPWIDGET 没有效果,因为非系统应用程序无法获得该权限(请参阅链接在我的问题中)。 2. 我正在使用我自己的“选择小部件活动”——ICS 启动器中内置的活动。我可能误解了,但我开始认为这是不可能的。
        • 可以授予什么权限取决于手机/设备的ROM。例如,我的三星时刻给了我该权限(非根)。摩托罗拉 Xoom (root) 不会授予该权限,但如果我没有它,它就会大喊大叫。
        • 真的吗?这是荒谬的!似乎有意不应该给出它。还是谢谢你的回答。
        • @Fuzzical Logic 您的方法只适用于旧的 AppWidgetPickActivity,而不是 ICS。因为 AppWidgetPickActivity 也使用了 mAppWidgetManager.bindAppWidgetId(mAppWidgetId, intent.getComponent());而它驻留在 System app: Settings 中,并且 Settings 有权限绑定 appwidget。
        • @herbertD:无意冒犯,但这正是我要说的。 “BIND_APPWIDGET”是系统权限,仅由系统使用。如果设置应用程序作为 ROM 的一部分安装,则允许设置。是的,我的方法是“旧方法”,但对象仍然存在于 ICS 中,并且它适用于使用 4.0 的启动器。事实上,这就是 OP 发表这篇文章的原因......因为 BIND_APPWIDGET 是 system 权限only。我的解决方案对您不起作用,因为您使用 custom 小部件选择器。如果您想找到解决方案,请更改您的选择器或提出新问题。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2021-05-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-11-21
        • 1970-01-01
        相关资源
        最近更新 更多