代码方式桌面添加AppWidget

本文详细介绍了在非标准安卓Launcher环境中将AppWidget添加至桌面的过程,包括获取ID、绑定组件及视图展示等步骤,并针对不同SDK版本提供了兼容性解决方案。

  前段时间做了个桌面的widget,第一次接触AppWidget,遇到了不少问题,今天整理下和大家探讨下.

  至于AppWidget的有些基础知识,我在这里就不多说了,大家有什么不明白,随便百度下,就有很多答案.今天主要说一下我在往桌面上添加时遇到的问题.

  

  如图所示,中间的Recommended就是一个appwidget添加在桌面上.下面我们就来说说添加的流程.

  首先,上面的页面不是手机页面,是阅读设备,用的是安卓系统,类似平板一样的设备.桌面也不是安卓原生的Luncher,所以也不可能像手机那样长按空白选择,然后滑动选择位置就添加上去了,而且还要求开机就默认在桌面上,位置也不能变(大笑我们也没做长按可以移动widget的功能).

  加载流程如下:

  1.获取ID

  2.获取appwidget的ComponentName

  3.绑定bindAppWidgetId

  4.获取AppWidgetHostView(RemoteViews并不是真的view)

  5.添加AppWidgetHostView到父Layput中

  代码如下:

  

private void addRecommendationsWidget() {
        int APPWIDGET_HOST_ID = 1024;
        AppWidgetHost appWidgetHost = new AppWidgetHost(getApplicationContext(), APPWIDGET_HOST_ID);
        int appWidgetId = appWidgetHost.allocateAppWidgetId();
        AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(getApplicationContext());
        List<AppWidgetProviderInfo> providers = appWidgetManager.getInstalledProviders();
        if (providers == null) {
            Log.e(TAG, "failed to find installed widgets ");
            return;
        }
        final int providerCount = providers.size();
        AppWidgetProviderInfo appWidgetProviderInfo = null;
        for (int i = 0; i < providerCount ; i++) {
            ComponentName provider = providers.get(i).provider;
            if (provider != null && provider.getPackageName().equals("com.xxxx.android.xxxx")) {
                appWidgetProviderInfo = providers.get(i);
                break;
            }
        }
        if (appWidgetProviderInfo == null) {
            Log.e(TAG, "failed to find recommendations widget ");
            return;
        }
        int sdkVersion = Integer.valueOf(android.os.Build.VERSION.SDK);
        if (sdkVersion > 15) {
            final String methodName = "bindAppWidgetIdIfAllowed";
            boolean success = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, methodName);
            if (!success) {
                addWidgetPermission(appWidgetManager);
                boolean bindAllowed = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, methodName);
                if (!bindAllowed) {
                    Log.e(TAG, " failed to bind widget id : " + appWidgetId);
                    return;
                }
            }
        } else {
            boolean success = bindAppWidgetId(appWidgetManager, appWidgetId, appWidgetProviderInfo.provider, "bindAppWidgetId");
            if (!success) {
                Log.e(TAG, " failed to bind widget id : " + appWidgetId);
                return;
            }
        }
        Log.d(TAG, " successful to bind widget id : " + appWidgetId);
        AppWidgetHostView hostView = appWidgetHost.createView(this, appWidgetId, appWidgetProviderInfo);
        appWidgetHost.startListening();
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, appWidgetProviderInfo.minHeight);
        RelativeLayout widgetLayout = (RelativeLayout) findViewById(R.id.recommendation_widget_layout);
        widgetLayout.addView(hostView, params);
    }

    private void addWidgetPermission(AppWidgetManager appWidgetManager) {
        String methodName = "setBindAppWidgetPermission";
        try {
            Class [] argsClass = new Class[]{String.class, boolean.class};
            Method method = appWidgetManager.getClass().getMethod(methodName, argsClass);
            Object [] args = new Object[]{this.getPackageName(), true};
            try {
                method.invoke(appWidgetManager, args);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    private boolean bindAppWidgetId(AppWidgetManager appWidgetManager, int appWidgetId, ComponentName componentName, String methodName) {
        boolean success = false;
        Class [] argsClass = new Class[]{int.class, ComponentName.class};
        try {
            Method method = appWidgetManager.getClass().getMethod(methodName, argsClass);
            Object [] args = new Object[]{appWidgetId, componentName};
            try {
                method.invoke(appWidgetManager, args);
                success = true;
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
        return success;
    }
  代码比较简单,一看应该就很清除.中间为什么要判断sdk版本呢?因为我发现4.0.4和4.2.2绑定的方法不一样,(我也只验证了这两个版本,其它的你们可以看文档)这里为了兼容,采用反射的方法绑定ID.

  4.0.4绑定ID用AppWidgetManager的bindAppWidgetId()函数,而且需要添加权限:

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

  4.2.2绑定ID用AppWidgetManager的bindAppWidgetIdIfAllowed()函数,同时会返回绑定结果的boolean值,而且需要添加权限:

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

  权限一定不要忘记,setBindAppWidgetPermission(true)这个函数是用来给添加到桌面上授权,可以避免添加时弹出需要授权的对话框(安卓系统的授权对话框).由于这个是hide API,所以也用反射的方式调用.

  最后一点切记,必须有System权限的app才能用这种方法,也就是安装在system/app下面的应用才可以.

  大家有什么不同的看法可以一起讨论!共同进步!下一篇我会讲一下appwidget滑动翻页的问题!第一次写博客,不足之处,请大家多多指正. 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值