Android开发 GCM实现前后台推送的功能

 前言:

由于项目要求在国外上线,所以我使用Google自带的GCM实现推送。GCM即Google Cloud Messaging,可以让开发者在客户端和服务器之间传递消息。GCM需要google service支持,在国内基本不能用,经常会断线,国内采用比较多的是极光、友盟、信鸽等第三方推送,GCM推送相关文章不多,下面简单总结一下我在项目中如何实现GCM前后台推送。

用到的知识点:

  1. Retrofit实现网络请求
  2. GCM+NotificationCompat/NotificationChannels实现后台推送
  3. EventBus+FragmentTabHost实现前台(底部导航)推送

实现的代码:

1.Google官网注册应用

   首先去网址:https://console.firebase.google.com/ 去注册自己的应用,并下载google-services.json的文件,把它放到自己项目的app/目录。

2.添加依赖

  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'    //这一句一定要放在最下面,否则无效

3.配置AndroidMenifest.xml文件

<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">
            <!--这里的resource的ic_notification要跟接口一致 -->
            <meta-data
                android:name="com.google.firebase.messaging.default_notification_icon"
                android:resource="@drawable/ic_notification" />
            <intent-filter>
                <action android:name="com.google.firebase.MESSAGING_EVENT" />
            </intent-filter>
        </service>
    </application>

</manifest>

4.MyFirebaseInstanceIDService获取token的接口

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接收推送

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

    public void onMessageReceived(RemoteMessage remoteMessage) {
        int type = 0;
        int count = 0;
        if (remoteMessage.getData().size() > 0) {
            datatype = Integer.valueOf(remoteMessage.getData().get("type"));
            count = Integer.valueOf(remoteMessage.getData().get("count"));

            if (datatype == 1 || datatype == 2) {   // 1和2都表示不同的类型                      EventBus.getDefault().post(new FcmMessageEvent(type, count));
            }

        }

        if (remoteMessage.getNotification() != null) {
            //show Notification
            Intent intent = new Intent(this, MainActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            intent.putExtra("type",type);
            PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
                    PendingIntent.FLAG_UPDATE_CURRENT);

            Bitmap bm = BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher);
            NotificationCompat.Builder notificationBuilder = (NotificationCompat.Builder) new NotificationCompat.Builder(this)
                    .setContentTitle(remoteMessage.getNotification().getTitle())
                    .setContentText(remoteMessage.getNotification().getBody())
                    .setLargeIcon(bm)
                    .setSmallIcon(R.drawable.ic_notification)
                    .setBadgeIconType(NotificationCompat.BADGE_ICON_SMALL)
                    .setDefaults(Notification.DEFAULT_ALL)
                    .setAutoCancel(true)
                    .setContentIntent(pendingIntent);

            NotificationManagerCompat notificationManagerCompat = NotificationManagerCompat.from(Global.mContext);

            //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);

            }

            notificationManagerCompat.notify(0, notificationBuilder.build());

        }

    }
}

6.MainActivity接收EventBus消息显示底部导航的未读消息

public class MainActivity extends BaseActivity{
    ...

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        EventBus.getDefault().register(this);//注册
    }
    /*
     *当有消息推送并且在前台运行的时候,会调用此方法
     */
    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onMessageEvent(FcmMessageEvent event) {
        type = 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 type2 = SharedPreUtil.getInt(Global.mContext, "type", 0);
        if (status == 1 || status == 2) {  //status为1是登录进来的状态,status为2是注册进来的状态
            if (type2 == 1) { //当type=1进去页面              
                tabHost.setCurrentTab(1);
                CreditReportFragment.position = 2;
                tabHost.getTabWidget().getChildAt(1).setBackgroundResource(R.color.colorAccent2);
                SharedPreUtil.saveInt(Global.mContext,"type",0);
            } else if (type2 == 2) {//当type2=2进去另一个页面
                tabHost.setCurrentTab(1);
                CreditReportFragment.position = 0;
                tabHost.getTabWidget().getChildAt(1).setBackgroundResource(R.color.colorAccent2);
                SharedPreUtil.saveInt(Global.mContext,"type",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() {
          //请求网络,将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);

    
        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.FcmMessageEvent的类

public class FcmMessageEvent {
    private int datatype;
    private int count;

    public FcmMessageEvent(int datatype, int count) {
        this.datatype = datatype;
        this.count = count;
    }

    public int getDatatype() {
        return datatype;
    }

    public void setDatatype(int datatype) {
        this.datatype = datatype;
    }

    public int getCount() {
        return count;
    }

    public void setCount(int count) {
        this.count = count;
    }


}

8.SettingNotificationsFragment推送的开关,用户可以决定要不要推送

public class SettingNotificationsFragment extends BaseFragment {
    ...

    @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
                        //请求推送的网络请求
                    }

                } else {
                    if (!TextUtils.isEmpty(uuid)) {
                        // 取消推送的网络请求
                    }
                }
            }
        });
        ....
       }
      ....

}

9.总结:

GCM前后台的推送功能已经实现啦,欢迎大家围观如果有什么疑问的话,可以留言联系我哦!

转载于:https://my.oschina.net/wupeilin/blog/1633145

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值