安卓推送功能小结(整合华为小米)

接手的项目里面有一个小米和华为混用的推送功能,虽然能用,但是代码写的非常乱,正好最近又看了点设计模式,就花了点时间重构了一下,顺便做一个小结!

具体如何导入各个厂商的 SDK,文章末尾会讲下小米的,这里先把如何混用先说完,下面给出华为小米得官网链接,需要的话可以根据官网教程导入:

  • 小米推送
    https://dev.mi.com/console/appservice/push.html
  • 华为推送
    https://developer.huawei.com/consumer/cn/hms/huawei-pushkit

下面先讲如何混用两个推送功能的思路

整体思路

因为涉及到多个推送服务的使用(考虑后面扩展),并且有类似的地方,所以我这抽象了一个推送服务接口(IPushClient),具体实现再根据厂商去实现。对于生成不同的推送服务,首先想到了工厂模式,下面也是这么做的,最后又写了一个 PushClientProxy 类来集中处理推送服务的功能,几个文件如下:

  • IPushClient 推送服务接口
    • PushClientProxy 代理类
    • HuaweiPushClient 华为推送服务
    • XiaomiPushClient 小米推送服务
  • PushClientFactory 用来生成推送服务的工厂类

对于接受消息,都是通过广播来接受,这里我没有整合在一起,所以有两个广播接收器要编写:

  • HuaweiPushReceiver
  • XiaomiPushReceiver

推送服务

public interface IPushClient {
    void bind();
    void unbind();
}

推送服务接口设计了两个功能,绑定和解绑推送功能,下面时华为和小米对应的推送服务。

  • 华为
public class HuaweiPushClient implements IPushClient, HuaweiApiClient.ConnectionCallbacks, HuaweiApiClient.OnConnectionFailedListener {

    private final HuaweiApiClient mClient;

    private WeakReference<Activity> currentActivity;

    private String mToken = null;

    public HuaweiPushClient(Context context) {
        mClient = new HuaweiApiClient.Builder(context)
                .addApi(HuaweiPush.PUSH_API)
                .addConnectionCallbacks(this)
                .addOnConnectionFailedListener(this)
                .build();
    }

    //在activity修改时需要调用此方法更新currentActivity,降低了耦合性,却增加了复杂度
    public void setCurrentActivity(Activity activity) {
        //这里WeakReference里面居然不让修改,只能每次重建一个
        currentActivity = new WeakReference<>(activity);
    }

    @Override
    public void bind() {
        //通过下面方
        mClient.connect(currentActivity.get());
        //下面通过BaseActivity拿到当前activity比较方便,却耦合了
        //mClient.connect(BaseActivity.getCurrentAty());
    }

    @Override
    public void unbind() {
        mClient.disconnect();
    }

    @Override
    public void onConnected() {
        //client连接到华为移动服务,获取token
        PendingResult<TokenResult> tokenResult = HuaweiPush.HuaweiPushApi.getToken(mClient);
        tokenResult.setResultCallback(result -> mToken = result.getTokenRes().getToken());
    }

    @Override
    public void onConnectionSuspended(int cause) {
        //当client变成断开状态时,重新连接
        mClient.connect(currentActivity.get());
    }

    @Override
    public void onConnectionFailed(ConnectionResult result) {
        //建立client到service的连接失败时调用
    }
}
  • 小米
public class XiaomiPushClient implements IPushClient {

    private final Context mContext;

    //填入官网申请到的APP_ID
    private static final String APP_ID = "";

    //填入官网申请到的APP_KEY
    private static final String APP_KEY = "";

    public XiaomiPushClient(Context context) {
        mContext = context;
    }

    @Override
    public void bind() {
        //初始化push推送服务
        MiPushClient.registerPush(mContext, APP_ID, APP_KEY);
    }

    @Override
    public void unbind() {
        //关闭推送服务
        MiPushClient.unregisterPush(mContext);
    }
}

可能 SDK 版本不同会有所出入,但是这里我觉得应该不难。

推送服务创建

对于推送服务的创建,我们是需要根据手机型号去判断的,这里先写了一个工具类来判断应该使用何种推送服务:

public class BrandUtils {

    public static final int HUAWEI = 1;

    public static final int XIAOMI = 2;

    //获取厂商
    public static int getBrand(Context context) {
        if (isHuaweiDevice(context)) {
            return HUAWEI;
        }else {
            //这里默认使用了小米
            return XIAOMI;
        }
    }

    //判断是否时华为手机
    private static boolean isHuaweiDevice(Context context) {
        if ("huawei".equalsIgnoreCase(Build.BRAND) || "HONOR".equalsIgnoreCase(Build.BRAND)) {

            //EMUI版本号
            int emuiApiLevel = 0;
            //华为移动服务版本号
            int mobileServiceVersionCode = 0;

            try {
                @SuppressLint("PrivateApi")
                Class<?> cls = Class.forName("android.os.SystemProperties");
                Method method = cls.getDeclaredMethod("get", String.class);
                emuiApiLevel = Integer.parseInt((String) method.invoke(cls, "ro.build.hw_emui_api_level"));

                PackageManager pm = context.getPackageManager();
                PackageInfo pi = pm.getPackageInfo("com.huawei.hwid", 0);
                if (pi != null) {
                    mobileServiceVersionCode = pi.versionCode;
                }
            } catch (Exception e) {
                e.printStackTrace();
            }

            //在低版本EMUI和华为移动服务上推送不太行
            return emuiApiLevel > 9 && mobileServiceVersionCode >= 20401300;
        }

        return false;
    }
}

然后是推送服务的工厂,根据使用的推送种类生成对应的推送服务实现类

public class PushClientFactory {

    //通过type生成推送服务
    public IPushClient getPushClient(int type, Context context) {
        switch (type) {
            case BrandUtils.HUAWEI:
                return new HuaweiPushClient(context);
            case BrandUtils.XIAOMI:
            default:
                return new XiaomiPushClient(context);
        }
    }
}

使用推送服务

因为我们需要根据不同的手机型号生成不同的推送服务,所以这里使用了代理模式

public class PushClientProxy implements IPushClient {

    private final IPushClient mClient;

    private final Context mContext;

    public PushClientProxy(Context context) {
        //获取上下文
        mContext = context;
        //获取厂商
        int brand = BrandUtils.getBrand(context);
        //推送服务工厂类
        PushClientFactory factory = new PushClientFactory();
        //根据厂商获得推送服务
        this.mClient = factory.getPushClient(brand, context);
    }

    @Override
    public void bind() {
        //判断是否要注册推送服务
        if (shouldInit(mContext)) {
            mClient.bind();
        }
    }

    @Override
    public void unbind() {
        mClient.unbind();
    }

    //来自小米demo,判断当前应用是否在运行
    private boolean shouldInit(Context context) {
        ActivityManager am = ((ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE));
        List<ActivityManager.RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = context.getPackageName();
        int myPid = android.os.Process.myPid();
        for (ActivityManager.RunningAppProcessInfo info : processInfos) {
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }
}

代理类创建的时候,会拿着上下文对象获得厂商类别,并生成对应的推送服务,这里需要在 application 中创建,并调用 bind 方法。

消息接受

这里写了两种广播接收器,具体看下面代码:

  • 华为
public class HuaweiPushReceiver extends PushReceiver {

    @Override
    public void onToken(Context context, String token, Bundle extras){
        //用来接收token和附加信息
        String belongId = extras.getString("belongId");
    }

    @Override
    public boolean onPushMsg(Context context, byte[] msg, Bundle bundle) {
        //用来接收透传消息
        String content = new String(msg, StandardCharsets.UTF_8);

        return false;
    }

    public void onEvent(Context context, Event event, Bundle extras) {
        //Push事件回调方法入口,目前支持的回调事件有通知栏消息点击事件回调、通知栏扩展消息按钮点击事件回调
        super.onEvent(context, event, extras);
    }

    @Override
    public void onPushState(Context context, boolean pushState) {
        //接收push连接状态
    }
}
  • 小米
public class XiaomiPushReceiver extends PushMessageReceiver {

    private String mRegId;

    @Override
    public void onNotificationMessageArrived(Context context, MiPushMessage message) {
        //获取通知栏推送消息
        String content = message.getContent();
    }


    @Override
    public void onReceivePassThroughMessage(Context context, MiPushMessage message) {
        //获取透传消息
        String content = message.getContent();
    }

    @Override
    public void onNotificationMessageClicked(Context context, MiPushMessage message) {
        //通知栏消息点击
    }

    @Override
    public void onReceiveRegisterResult(Context context, MiPushCommandMessage message) {
        //注册结果,可以拿到mRegId
        String command = message.getCommand();
        List<String> arguments = message.getCommandArguments();
        String cmdArg1 = ((arguments != null && arguments.size() > 0) ? arguments.get(0) : null);
        if (MiPushClient.COMMAND_REGISTER.equals(command)) {
            if (message.getResultCode() == ErrorCode.SUCCESS) {
                mRegId = cmdArg1;
            }
        }
    }
}

这里应该也可以把各个接收的消息统一起来,需要和业务挂钩吧,读者自行处理喽!

接入小米推送

本文开头说了会介绍一下接入小米推送,其他的应该都差不多,下面看步骤:

  1. 在小米推送运营平台创建应用,地址点这里, 获取到 AppID 和 AppKey

  2. 把从小米下载的 jar 导入到安卓项目中

  3. 在 AndroidManifest.xml 中添加权限

     <uses-permission android:name="android.permission.INTERNET" />
     <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
     <uses-permission android:name="android.permission.READ_PHONE_STATE" />
     <uses-permission android:name="android.permission.GET_TASKS" />
     <uses-permission android:name="android.permission.VIBRATE"/>
     <permission android:name="com.xxx.xxx.permission.MIPUSH_RECEIVE" android:protectionLevel="signature" />
     <uses-permission android:name="com.xxx.xxx.permission.MIPUSH_RECEIVE" />
    
  4. 在 AndroidManifest.xml 中配置推送服务需要的service和receiver

     <service
       android:enabled="true"
       android:process=":pushservice"
       android:name="com.xiaomi.push.service.XMPushService"/>
     <service
       android:name="com.xiaomi.push.service.XMJobService"
       android:enabled="true"
       android:exported="false"
       android:permission="android.permission.BIND_JOB_SERVICE"
       android:process=":pushservice" />
     <!--注:此service必须在3.0.1版本以后(包括3.0.1版本)加入-->
     <service
       android:enabled="true"
       android:exported="true"
       android:name="com.xiaomi.mipush.sdk.PushMessageHandler" /> 
     <service android:enabled="true"
       android:name="com.xiaomi.mipush.sdk.MessageHandleService" /> 
     <!--注:此service必须在2.2.5版本以后(包括2.2.5版本)加入-->
     <receiver
       android:exported="true"
       android:name="com.xiaomi.push.service.receivers.NetworkStatusReceiver" >
       <intent-filter>
         <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
         <category android:name="android.intent.category.DEFAULT" />
       </intent-filter>
     </receiver>
     <receiver
       android:exported="false"
       android:process=":pushservice"
       android:name="com.xiaomi.push.service.receivers.PingReceiver" >
       <intent-filter>
         <action android:name="com.xiaomi.push.PING_TIMER" />
       </intent-filter>
     </receiver>
    
  5. 自定义广播接收器继承 PushMessageReceiver 类接收推送消息(前面已写)

  6. 在 AndroidManifest.xml 中注册该广播

     <receiver
         android:name=".XiaomiPushReceiver"
         android:exported="true">
         <intent-filter>
             <action android:name="com.xiaomi.mipush.RECEIVE_MESSAGE"/>
         </intent-filter>
         <intent-filter>
             <action android:name="com.xiaomi.mipush.MESSAGE_ARRIVED"/>
         </intent-filter>
         <intent-filter>
             <action android:name="com.xiaomi.mipush.ERROR"/>
         </intent-filter>
     </receiver>
    
  7. 在 Application 中初始化推送服务(前面代理类作用)

结语

写下来感觉自己文笔不是很流畅,请读者见谅,不过我自己觉得设计模式写的还可以。

end

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值