Retrofit+GCM+FragmentTabHost realizes client front and back push

 Foreword:

Since the project is required to be launched abroad, I use Google's own GCM to implement push. GCM stands for Google Cloud Messaging, which allows developers to pass messages between clients and servers. GCM needs the support of google service, it is basically unusable in China, and the connection is often disconnected. In China, third-party pushes such as Jiguang, Youmeng, and Carrier Pigeon are mostly used. There are not many articles about GCM pushes. Realize GCM front-end and back-end push.

Knowledge points used:

  1. Retrofit implements network requests
  2. GCM+NotificationCompat/NotificationChannels realize background push
  3. EventBus+FragmentTabHost realizes front-end (bottom navigation) push

Implemented code:

1. Google official website registration application

   First go to the URL: https://console.firebase.google.com/  to register your own application, download the google-services.json file, and put it in the app/ directory of your own project.

2. Add dependencies

  2.1 Project的build.gradle
        classpath 'com.google.gms:google-services:3.1.0'    

  2.2  Module的build.gradle

        dependencies {
         //GCM
        compile 'com.google.firebase:firebase-core:11.0.4'
        compile 'com.google.firebase:firebase-messaging:11.0.4'
        }
         apply plugin: 'com.google.gms.google- services' //This sentence must be placed at the bottom, otherwise it is invalid

3. Configure the AndroidMenifest.xml file

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="项目包名">

    <!--连接网络权限-->
    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <!--保证消息到达的时候,可以得到及时处理-->
    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <!--声音震动的权限-->
    <uses-permission android:name="android.permission.VIBRATE"/>

    <application
        android:name="uk.co.common.base.MyApp"
        android:allowBackup="true"
        android:icon="@drawable/app_icon"
        android:label="@string/app_name"
        android:supportsRtl="true"
        android:theme="@style/AppTheme">
        <activity
            android:name=".ui.activity.SplashActivity"
            android:launchMode="standard"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity>
	 ...
        </activity>
   
        <service android:name=".ui.service.MyFirebaseInstanceIDService">
            <intent-filter>
                <action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
            </intent-filter>
        </service>
        <service android:name=".ui.service.MyFirebaseMessagingService">
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>

</manifest>

 

4. MyFirebaseInstanceIDService obtains the token interface

public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
    private static final String TAG = "MyFirebaseIIDService";

    @Override
    public void onTokenRefresh() {
        //获取token
        String token = FirebaseInstanceId.getInstance().getToken();
        SharedPreUtil.saveString(this, "fcm_token", token);//保存token
    }
}

 5. MyFirebaseMessagingService receives push

/*
*判断当前的app运行状态,如果app在前台运行的话就把消息推送底部导航,显示未读信息;如果app在后台运行(包括锁屏状态)就Notification通知
*/
public class MyFirebaseMessagingService extends FirebaseMessagingService {
    private NotificationManager notificationManager = null;

    public MyFirebaseMessagingService() {
    }

    public void onMessageReceived(RemoteMessage remoteMessage) {
        int datatype = 0;//推送的类型,本项目有New Alert和Score change两种类型的推送
        int count = 0; //推送的条数
        if (remoteMessage.getData().size() > 0) {
            datatype = Integer.valueOf(remoteMessage.getData().get("datatype"));
            count = Integer.valueOf(remoteMessage.getData().get("count"));
            SharedPreUtil.saveInt(Global.mContext,"datatype",datatype);

        }

        /*
         *获取app当前的运行状态
         */
        ActivityManager activityManager = (ActivityManager) Global.mContext.getSystemService(Context.ACTIVITY_SERVICE);
        List<ActivityManager.RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
        if (appProcesses.size() > 0) {
            ActivityManager.RunningAppProcessInfo appProcess = appProcesses.get(0);
            if (appProcess.processName.equals(Global.mContext.getPackageName())) {
                //app在前台运行
                if (datatype == 1 || datatype == 2) {   // 1:new Alert 2:score change
                    //使用EventBus发送信息,在MainActivity的onMessageEvent接收
                    EventBus.getDefault().post(new MessageEvent(datatype, count));
                }

            } else { 
                //app在后台运行,展示Notification
                if (remoteMessage.getNotification() != null) {
                    //点击Notification进入的页面
                    Intent intent = new Intent(this, MainActivity.class);
                    intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
                    PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                            PendingIntent.FLAG_UPDATE_CURRENT);
                    //Android8.0及其以上的适配
                    if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
                        CharSequence adminChannelName = remoteMessage.getNotification().getTitle();
                        String adminChannelDescription = remoteMessage.getNotification().getBody();
                        NotificationChannel adminChannel;
                        adminChannel = new NotificationChannel("", adminChannelName, NotificationManager.IMPORTANCE_LOW);
                        adminChannel.setDescription(adminChannelDescription);
                        adminChannel.setShowBadge(false);
                        if (notificationManager != null) {
                            notificationManager.createNotificationChannel(adminChannel);
                        }
                        NotificationCompat.Builder builder = new NotificationCompat.Builder(Global.mContext);
                        builder.setContentIntent(pendingIntent);

                    } else {
                        //Android7.0及其以下
                        NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                                .setSound(android.provider.Settings.System.DEFAULT_NOTIFICATION_URI)
                                .setSmallIcon(R.drawable.app_icon)
                                .setContentTitle(remoteMessage.getNotification().getTitle())
                                .setContentText(remoteMessage.getNotification().getBody())
                                .setDefaults(Notification.DEFAULT_ALL)
                                .setAutoCancel(true)
                                .setContentIntent(pendingIntent);

                        NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(Global.mContext);
                        notificationManagerCompat.notify(0, notificationBuilder.build());

                    }

                }
            }
        }

    }

}

6.MainActivity receives the EventBus message and displays the unread message of the bottom navigation

public class MainActivity extends BaseActivity{
    private FragmentTabHost tabHost;
    private CommonPresenter commonPresenter;
    private TextView tv_report_num;
    private int datatype;
    private int count;
    ...
     @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);//注册
    }
    /*
     *当有消息推送并且在前台运行的时候,会调用此方法
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(MessageEvent event) {
        datatype = event.getDatatype();
        count = event.getCount();
        int curtab = tabHost.getCurrentTab();//获取当前的tab
        tabHost.clearAllTabs();//清空之前的tab,因为已经初始化过一次了
        //update indicator
        for (int i = 0; i < texts.length; i++) {
            TabHost.TabSpec tabSpec = tabHost.newTabSpec(texts[i]);
            if (i == 1) { //Creidit Report
                if (count > 0) { //count有数据的话,显示未读条数
                    View v = getIndicatorView(texts[1], count, imageButton[1]);
                    tabSpec.setIndicator(v);
                    tabHost.addTab(tabSpec, fragments[i], null);
                } else { //count为0,隐藏未读条数
                    View v = getIndicatorView(texts[i], 0, imageButton[i]);
                    tabSpec.setIndicator(v);
                    tabHost.addTab(tabSpec, fragments[i], null);
                }

            } else {
                View v = getIndicatorView(texts[i], 0, imageButton[i]);
                tabSpec.setIndicator(v);
                tabHost.addTab(tabSpec, fragments[i], null);
            }
        }
        tabHost.setCurrentTab(2);//这句代码要加上,否则第一个tab会出现白屏
        tabHost.setCurrentTab(curtab);//设置当前的tab
    }

       @Override
    protected void onResume() {
        //app在后台运行,点击Notification进入的页面
        int status = SharedPreUtil.getInt(Global.mContext, "status", 0);
        int datatype2 = SharedPreUtil.getInt(Global.mContext, "datatype", 0);
        if (status == 1 || status == 2) {  //status为1是登录进来的状态,status为2是注册进来的状态
            if (datatype2 == 1) { //当datatype2为1是New Alert类型,进入alert页面               
                tabHost.setCurrentTab(1);
                CreditReportFragment.position = 2;
                tabHost.getTabWidget().getChildAt(1).setBackgroundResource(R.color.colorAccent2);
                SharedPreUtil.saveInt(Global.mContext,"datatype",0);
            } else if (datatype2 == 2) {//当datatype2为2是Score change类型s,进入summary页面
                tabHost.setCurrentTab(1);
                CreditReportFragment.position = 0;
                tabHost.getTabWidget().getChildAt(1).setBackgroundResource(R.color.colorAccent2);
                SharedPreUtil.saveInt(Global.mContext,"datatype",0);
            }else {
                int currentTab = tabHost.getCurrentTab();
                tabHost.setCurrentTab(currentTab);
            }
        } else {//如果status既不是1,也不是2,要求用户直接登录
            startActivity(new Intent(MainActivity.this, LoginActivity.class));
            finish();
        }

        super.onResume();
    }
    
    @Override
    public void onDestroy() {
        super.onDestroy();
        EventBus.getDefault().unregister(this);//反注册
    }
    
    @Override
    public void initView() {
        tabHost = (FragmentTabHost) findViewById(R.id.tab_host);
        tabcontent = (FrameLayout) findViewById(R.id.tabcontent);
        tabHost.setup(this, getSupportFragmentManager(), R.id.tabcontent);
        //Add indicator
        for (int i = 0; i < texts.length; i++) {
            TabHost.TabSpec tabSpec = tabHost.newTabSpec(texts[i]);
            View v = getIndicatorView(texts[i], 0, imageButton[i]);
            tabSpec.setIndicator(v);
            tabHost.addTab(tabSpec, fragments[i], null);
        }
        ...
    }

     @Override
    public void initData() {
        //Retrofit请求网络
        commonPresenter = new CommonPresenter(this);
        String token = SharedPreUtil.getString(Global.mContext, "fcm_token", "");//取token
        commonPresenter.postFcm(uuid, token);//将token的值发送给服务器,服务器收到后会推送消息
    }
    
     /*
      *获取底部导航icon和text,显示与隐藏未读条数的方法
      */
     private View getIndicatorView(String name, int num, int imgId) {
        //R.layout.guide_indicator_item:底部导航的icon和text布局
        View indicatorView = View.inflate(this, R.layout.guide_indicator_item, null);
        ImageView img = (ImageView) indicatorView.findViewById(R.id.img_indicator);
        tv_report_num = (TextView) indicatorView.findViewById(R.id.tv_report_num);//默认GONE
        TextView tv = (TextView) indicatorView.findViewById(R.id.tv_indicator);

        tv_report_num.setTypeface(Const.font700);

        if (num == 0) {
            tv_report_num.setVisibility(View.GONE);

        } else {
            tv_report_num.setVisibility(View.VISIBLE);
            if (num > 99) {
                tv_report_num.setText(String.valueOf(num) + "+");
            } else {
                tv_report_num.setText(String.valueOf(num));
            }

        }
        tv.setText(name);
        img.setBackgroundResource(imgId);
        return indicatorView;
    }

}

7. The switch of SettingNotificationsFragment push, the user can decide whether to push or not

public class SettingNotificationsFragment extends BaseFragment {
    private TextView tvNotifications;
    private Switch switchPush;
    private Switch switchApp;
    private CommonPresenter commonPresenter;

    @Override
    public int getLayoutRes() {
        return R.layout.setting_notifications;
    }

    @Override
    public void initView() {
        tvNotifications = (TextView) findView(R.id.tv_notifications);
        switchPush = (Switch) findView(R.id.switch_push);
        switchApp = (Switch) findView(R.id.switch_app);
        switchPush.setChecked(true);//默认选中
        switchApp.setChecked(true);
    }

    @Override
    public void initData() {
        //Retrofit请求网络
        commonPresenter = new CommonPresenter(this);
    }

    @Override
    public void onClick(View v, int id) {

        switchPush.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                if (isChecked) {
                    if (!TextUtils.isEmpty(uuid)) {
                        String token = SharedPreUtil.getString(Global.mContext, "fcm_token", "");//取token
                        commonPresenter.postFcm(uuid, token);//请求推送
                    }

                } else {
                    if (!TextUtils.isEmpty(uuid)) {
                        commonPresenter.deleteFcm(uuid);//取消推送
                    }
                }
            }
        });
        ....
       }
      ....

}

8. Summary:

The push function of the front and back ends of GCM has been implemented. If you have any questions, you can leave a message and contact me!

           

      

 

 

 

 

Guess you like

Origin http://10.200.1.11:23101/article/api/json?id=326996325&siteId=291194637