美文网首页
组件化二(消息推送)

组件化二(消息推送)

作者: 火星局 | 来源:发表于2018-10-17 16:45 被阅读0次

一、背景

根据不同的需求App会集成第三方消息推送,如极光,个推等并且他们都有自己的快捷集成方式。当公司项目比较多时,每个项目都要重新集成 很麻烦。刚好公司有新的系统上线,系统里面包含几大模块。如淘宝,携程,美团等业务模块很多,项目用组件化方式去写。顺便把消息推送重新封装,每次只需要做最基本的配置就可以了。

实现项目集成开发或组件开发时都已轻松的使用消息推送。当有新通知并点击,可以跳转到想到达的页面。需求很简单,现实很无奈,不断的尝试,才有了这篇文章。

二、推送组件

1.项目结构

image.png

随着项目的业务越多,公共组件common应该越来越小。本着此原则,决定把消息推送独立出来(90%独立)。实现的效果: 集成开发时,点击消息通知,根据消息的类型,去跳转所在的module_demoX。组件开发时,点击消息,跳转到此组件的主页面。很绕口,简单说lib中如何跳转到其他lib中的页面。

2.引入个推

  • 1). 基本配置及添加项目依赖
    新建library 命名common_push。在此lib中做个推基本配置(其过程一把心酸一把泪)。
 1.添加maven库
allprojects {
    repositories {
        google()
        jcenter()
        //Maven URL地址
        maven {
            url "http://mvn.gt.igexin.com/nexus/content/repositories/releases/"
        }

    }
}

2.gradle.properties配置
android.useDeprecatedNdk=true

3.添加NDK和manifestPlaceholders
defaultConfig {
     ...........
        ndk {
            abiFilters "armeabi", "armeabi-v7a", "x86_64"
        }
        manifestPlaceholders = [
                GETUI_APP_ID    : "4XEAxE8s4F6J64oPemLGZ7",
                GETUI_APP_KEY   : "NLJ1HSIpZr6siNGID87cb3",
                GETUI_APP_SECRET: "lRCYFUiCirAG9EChR1KcG"
        ]
    }

  4.添加第三方gson,公共组件common的依赖
此项目使用组件化开发,路由是必备,这里引入common组件也不算过分。自我感觉良好,哈哈哈。
使用common中路由来实现页面跳转,因此造成90%的独立common组件,如更好的方法,欢迎留言。

  dependencies {
    implementation fileTree(include: ['*.jar'], dir: 'libs')
    api 'com.getui:sdk:2.12.5.0'
    implementation 'com.google.code.gson:gson:2.2.4'
    implementation 'com.android.support:appcompat-v7:26.1.0'
    implementation project(':common')
  }

5.添加权限
<!-- iBeancon功能所需权限 -->
    <uses-permission android:name="android.permission.BLUETOOTH" />
    <uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
    <!-- 个推3.0电子围栏功能所需权限 -->
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
    <!-- 配置的第三方参数属性 -->
    <uses-permission android:name="android.permission.VIBRATE" />

    <application android:usesCleartextTraffic="true">
        <service
            android:name=".PushServie.PushService"
            android:exported="true"
            android:label="PushService"
            android:process=":pushservice" />
        <service android:name=".PushServie.PushIntentService" />
        <service android:name=".PushServie.IntentActService" />
    </application>

6.超级大坑(只显示结果,不记录过程)
在空壳main组件和app中的gradle,分别配置manifestPlaceholders ,否则编译报错

        manifestPlaceholders = [
                GETUI_APP_ID    : "4XEAxE8s4F6J64oPemLGZ7",
                GETUI_APP_KEY   : "NLJ1HSIpZr6siNGID87cb3",
                GETUI_APP_SECRET: "lRCYFUiCirAG9EChR1KcG"
        ]

7.消息到达的目的不同
集成模式下:在空壳main组件gradle添加common_push依赖。
组件模式下:这里是为module添加的消息推送,所以在gradle中添加common_push的依赖。

  • 2).消息服务重写以及生成通知


    image.png

1.新建PushIntentService 继承GTIntentService ,PushService 继承Service ,这是个推文档里的要求,这里不做过多的描述

2.新建PushNotification工具类。
这里采用透传消息方式,所以需要自己新建一个通知。通知包含自定义铃声,显示应用的logo,名字等。

3.页面跳转(最蛋疼的地方)的通知
如果此工具类在存在业务组件中,页面跳转很简单,只需要制定一个Activity即可。但这里是lib形式的组件,Activity无法直接指定,造成无法跳转,摸索了大半天。
中间想过使用广播,静态注册,利用隐式跳转的方式,在需要跳转的组件中接收次广播即可做跳转的操作。大家都知道在android O中 谷歌取消了大部分广播的静态注册方式,只保留了部分广播的静态注册,此方法废弃。
静态不行,动态这次可以了吧,但是思考一下,还是放弃了。原因你懂的........
最后还是采用service的方式。点击通知时启动service,在service中通过路由去跳转页面。

        Intent mainIntent = new Intent(context, IntentActService.class);
        mainIntent.putExtra(ConfigPush.intentActData, String.valueOf(bean.getType()));
        PendingIntent mainPendingIntent = PendingIntent.getService(context, 0, mainIntent, PendingIntent.FLAG_UPDATE_CURRENT);
  
  • 3).实现思路
    伪代码
1.新建IntentActService 服务,在onStartCommand 中接收 通知跳转带来的值 ,并调用PushUtils中的IntentActAroute方法实现跳转。
    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        String data = intent.getExtras().getString(ConfigPush.intentActData);
        Log.i("stf", "--IntentActService-->" + data);
        PushUtils.getInstance(IntentActService.this).IntentActAroute(data);
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                stopSelf();
            }
        }, 3000);
        return START_NOT_STICKY;
    }

 2.PushUtils工具类中的路由相关
// 根据不同的路由跳转
 public void IntentActAroute(String type) {
        Log.i("stf", "--IntentActAroute--->" + type.toString());
        try {
            Map<String, String> aRouteMap = getARouteMap();
            if (aRouteMap != null && aRouteMap.size() > 0) {
                String url = aRouteMap.get(type);
                Log.i("stf", "--url--->" + url);
                ARouter.getInstance().build(url).navigation();
            }
        } catch (Exception e) {
            e.fillInStackTrace();
            Log.i("stf", "-IntentActAroute--->" + e.getMessage());
        }

    }

  // 将需要跳转的页面的路由地址与通知的类型绑定,初始化的时候把数据带进来

 public static Boolean setARouteMap(Map<String, String> mapAroute) {
        boolean result = false;
        JSONArray mJsonArray = new JSONArray();
        SharedPreferences shared = context.getSharedPreferences(ConfigPush.sharedMsg, Context.MODE_MULTI_PROCESS);
        SharedPreferences.Editor edit = shared.edit();
        edit.remove(ConfigPush.saveMap).commit();
        try {
            Iterator<Map.Entry<String, String>> iterator = mapAroute.entrySet().iterator();
            JSONObject object = new JSONObject();
            while (iterator.hasNext()) {
                Map.Entry<String, String> entry = iterator.next();
                object.put(entry.getKey(), entry.getValue());
            }
            mJsonArray.put(object);
            edit.putString(ConfigPush.saveMap, mJsonArray.toString());
            result = true;
        } catch (Exception e) {
            e.fillInStackTrace();
            result = false;
        }
        edit.apply();
        return result;
    }

// 取出路由路径的map
 private Map<String, String> getARouteMap() {
        SharedPreferences shared = context.getSharedPreferences(ConfigPush.sharedMsg, Context.MODE_MULTI_PROCESS);
        Map<String, String> map = new LinkedHashMap<>();
        map.clear();
        String json = shared.getString(ConfigPush.saveMap, "1");
        if (json.equals("1")) {
            return map;
        }
        try {
            JSONArray array = new JSONArray(json);
            JSONObject itemObject = array.getJSONObject(0);
            JSONArray names = itemObject.names();
            if (names != null) {
                for (int j = 0; j < names.length(); j++) {
                    String name = names.getString(j);
                    String value = itemObject.getString(name);
                    map.put(name, value);
                }
            }
        } catch (Exception e) {
            e.fillInStackTrace();
            Log.i("stf", "-getARouteMap--->" + e.fillInStackTrace());
        }
        return map;
    }

  • 4)初始化个推以及相关数据
 1.MyApp中初始化路由

    集成模式或组件模式分别有自己的appliction 
        if (ApiUtils.isAppDeBug()) {
            ARouter.openDebug();
            ARouter.openLog();
        }
        ARouter.init(this);

2. 集成模式下的空壳main组件中初始化路由路径
        PushUtils.init(this);
        PushUtils.initialize();
        PushUtils.turnOnPush();
        PushUtils.setPushUtils(this);//需要实现接口
        
        这里的map的key :1,2,3是后台发出来通知的json数据,有个type的字段。
        Map<String, String> mapAroute = new LinkedHashMap<>();
        mapAroute.put("1", Config.demo1_mainAct);
        mapAroute.put("2", Config.demo2_mainAct);
        mapAroute.put("3", Config.mainAct);
        PushUtils.setARouteMap(mapAroute);

3.组件模式下module_dem2的loginAct页面中
        PushUtils.init(this);
        PushUtils.initialize();
        PushUtils.turnOnPush();
        PushUtils.setPushUtils(this);//需要实现接口
        
  
        Map<String, String> mapAroute = new LinkedHashMap<>();
        mapAroute.put("2", Config.demo2_mainAct);
        PushUtils.setARouteMap(mapAroute);
  
    
4.页面的路由配置
  组件中如:
       @Route(path = Config.demo2_mainAct)
       public class MainActMod2 extends AppCompatActivity implements PushInterface {
        }

        @Route(path = Config.mainAct)
        public class MainActivity extends BaseActivity{
       } 

 5.个推的clientid,通知消息数据的获取

   比如进入某页面启动个推时,可以在次页面中实现PushInterface 接口并实现其onReceiveClientId(String id),
   onReceiveMessageData(String msg)方法,即可获取clientid和推送json数据。

    另一种获取clientid的方式,可以调用PushUtils.getInstance(this).getClientId()方法,其返回值就是clientid。
    注意当期返回值为null时,需要再利用onReceiveClientId方法来获取。

    @Route(path = Config.demo2_mainAct)
    public class MainActMod2 extends AppCompatActivity implements PushInterface {
    }

    public void getClientId(View view) {
        String clientId = PushUtils.getInstance(this).getClientId();
        Log.i("stf", "-LoginActiMode2-clientId--->" + clientId);
    }

    @Override
    public void onReceiveClientId(String id) {
        Log.i("stf", "-LoginActiMode2-clientId--->" + id);
    }

    @Override
    public void onReceiveMessageData(String msg) {
        Log.i("stf", "-LoginActiMode2-msg--->" + msg);
    }


  • 5)大功告成,此时可以随意切换集成模式和组件模式,来测试通知,亲测可行。

三、参考

代码传送门
组件化一(项目搭建)

相关文章

网友评论

      本文标题:组件化二(消息推送)

      本文链接:https://www.haomeiwen.com/subject/qkurzftx.html