Android 极光推送API

简介: Android 极光推送API

前言


发现现在的Android开发中很少有不用第三方SDK的,为什么呢?就是因为实现一个功能的速度快呀,比如说客服、聊天、直播等一些功能,用第三方SDK可以最快解决问题,我在实际开发中也对接过很多SDK,不过仔细写过这方便到的博客,前段时间我写了一个关于udesk SDK的文章,实现IM的,写的不算太详细,不过你如果看了也够用了,好了,进入正文。


正文


效果图,源码在文章最后

20200518181719843.png


今天要对接的这个SDK是极光系列中的推送服务SDK,当然极光还有其他的服务,进入极光官网了解一下,我这里放个图说明一下


20200517203723989.png


主要看我标注的这个,因为主要讲这个,为什么文章会说是详细到令人发指呢?下面你就明白了。


注册极光账号


无论你用什么SDK,你都会需要注册账号的,为了写个博客我都重新注册了一个账号了,点击注册


20200517204634567.png


进入注册页面


20200517204518965.png


输入个人信息,


20200517204930945.png


然后提交


20200517205014243.png

然后要进入邮箱去验证一下,不然怎么知道你这个邮箱有没有用呢,点击立即登录邮箱,进入之后打开收件箱


20200517205147484.png


可以看到最新的邮件是极光发过来的,打开这个邮件


20200517205347417.png


然后进行邮箱验证


20200517205437502.png


有的电脑可能又会这根访问拦截,点继续访问即可,没出现的当我没说过。

20200517205538302.png


邮箱验证成功,登录极光吧!

20200517205649775.png


输入信息之后登录

20200517210719103.png


这个信息现在是可以随便输入的,不过如果你要升级为开发者的话就要真实个人信息了。

20200517212956130.png


进入开发者平台

20200517213242200.png



创建应用,需要名称和图标


20200517223005594.png


这里需要用到一个图标

2020051722302921.png

点击确认,然后应用就创建好了

20200517223311404.png


接下来进行推送设置

20200517225151316.png


应用包名,现在去Android Studio创建一个项目

20200517225418180.png


Next

20200517225558410.png


Finish,等待项目创建完成,打开AndroidManifest.xml

20200517231011466.png


复制包名

20200517231244611.png

保存

20200517232827294.png


确认

20200517233043629.png


查看集成文档

20200518163627335.png


主要看这个自动集成的,简单快捷,So Easy!

文档你可以自己去看,因为我已经看过很多遍了,所以下面以项目的环境为主。



步骤


① 确认 android studio 的 Project 根目录的主 gradle 中配置了 jcenter 支持。(新建 project 默认配置就支持)

20200518163957736.png

20200518165532310.png


② 在 module 的 gradle 中添加依赖。

20200518171440709.png

20200518171626974.png


然后右上角Sync Now点击同步一下刚才改变的配置,否则改动不生效。


③ 然后新建两个包,servicereceiver

20200518172029948.png

202005181723439.png

20200518172416791.png


然后在service包下创建一个PushService类,然后继承JCommonService,代码如下:

package com.llw.pushdemo.service;
import cn.jpush.android.service.JCommonService;
public class PushService extends JCommonService {
}


在receiver包下创建一个PushReceiver类,然后继承JPushMessageReceiver,代码如下:


package com.llw.pushdemo.receiver;
import cn.jpush.android.service.JPushMessageReceiver;
public class PushReceiver extends JPushMessageReceiver {
}


都只是简单的继承而已。


④ 配置AndroidManifest.xml


然后现在回到AndroidManifest.xml


20200518173337749.png


    <!--极光推送 服务-->
        <service
            android:name=".service.PushService"
            android:enabled="true"
            android:exported="false"
            android:process=":pushcore">
            <intent-filter>
                <action android:name="cn.jiguang.user.service.action" />
            </intent-filter>
        </service>
        <!--极光推送 接收器-->
        <receiver
            android:name=".receiver.PushReceiver"
            android:enabled="true"
            android:exported="false" >
            <intent-filter>
                <action android:name="cn.jpush.android.intent.RECEIVE_MESSAGE" />
                <category android:name="com.llw.pushdemo" />
            </intent-filter>
        </receiver>


这里会用到一个工具类ExampleUtil.java,代码如下:


package com.llw.pushdemo;
import android.content.Context;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Bundle;
import android.os.Looper;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.widget.Toast;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import cn.jpush.android.api.JPushInterface;
import cn.jpush.android.helper.Logger;
public class ExampleUtil {
    public static final String PREFS_NAME = "JPUSH_EXAMPLE";
    public static final String PREFS_DAYS = "JPUSH_EXAMPLE_DAYS";
    public static final String PREFS_START_TIME = "PREFS_START_TIME";
    public static final String PREFS_END_TIME = "PREFS_END_TIME";
    public static final String KEY_APP_KEY = "JPUSH_APPKEY";
    public static boolean isEmpty(String s) {
        if (null == s)
            return true;
        if (s.length() == 0)
            return true;
        if (s.trim().length() == 0)
            return true;
        return false;
    }
    /**
     * 只能以 “+” 或者 数字开头;后面的内容只能包含 “-” 和 数字。
     * */
    private final static String MOBILE_NUMBER_CHARS = "^[+0-9][-0-9]{1,}$";
    public static boolean isValidMobileNumber(String s) {
        if(TextUtils.isEmpty(s)) return true;
        Pattern p = Pattern.compile(MOBILE_NUMBER_CHARS);
        Matcher m = p.matcher(s);
        return m.matches();
    }
    // 校验Tag Alias 只能是数字,英文字母和中文
    public static boolean isValidTagAndAlias(String s) {
        Pattern p = Pattern.compile("^[\u4E00-\u9FA50-9a-zA-Z_!@#$&*+=.|]+$");
        Matcher m = p.matcher(s);
        return m.matches();
    }
    // 取得AppKey
    public static String getAppKey(Context context) {
        Bundle metaData = null;
        String appKey = null;
        try {
            ApplicationInfo ai = context.getPackageManager().getApplicationInfo(
                    context.getPackageName(), PackageManager.GET_META_DATA);
            if (null != ai)
                metaData = ai.metaData;
            if (null != metaData) {
                appKey = metaData.getString(KEY_APP_KEY);
                if ((null == appKey) || appKey.length() != 24) {
                    appKey = null;
                }
            }
        } catch (NameNotFoundException e) {
        }
        return appKey;
    }
    // 取得版本号
    public static String GetVersion(Context context) {
    try {
      PackageInfo manager = context.getPackageManager().getPackageInfo(
          context.getPackageName(), 0);
      return manager.versionName;
    } catch (NameNotFoundException e) {
      return "Unknown";
    }
  }
    public static void showToast(final String toast, final Context context)
    {
      new Thread(new Runnable() {
      @Override
      public void run() {
        Looper.prepare();
        Toast.makeText(context, toast, Toast.LENGTH_SHORT).show();
        Looper.loop();
      }
    }).start();
    }
    public static boolean isConnected(Context context) {
        ConnectivityManager conn = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);
        NetworkInfo info = conn.getActiveNetworkInfo();
        return (info != null && info.isConnected());
    }
  public static String getImei(Context context, String imei) {
        String ret = null;
    try {
      TelephonyManager telephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
            ret = telephonyManager.getDeviceId();
    } catch (Exception e) {
      Logger.e(ExampleUtil.class.getSimpleName(), e.getMessage());
    }
    if (isReadableASCII(ret)){
            return ret;
        } else {
            return imei;
        }
  }
    private static boolean isReadableASCII(CharSequence string){
        if (TextUtils.isEmpty(string)) return false;
        try {
            Pattern p = Pattern.compile("[\\x20-\\x7E]+");
            return p.matcher(string).matches();
        } catch (Throwable e){
            return true;
        }
    }
    public static String getDeviceId(Context context) {
        return JPushInterface.getUdid(context);
    }
}

20200518173844372.png


⑤ 修改MainActivity.java


然后是MainActiviity.java

//for receive customer msg from jpush server
    private MessageReceiver mMessageReceiver;
    public static final String MESSAGE_RECEIVED_ACTION = "com.example.jpushdemo.MESSAGE_RECEIVED_ACTION";
    public static final String KEY_TITLE = "title";
    public static final String KEY_MESSAGE = "message";
    public static final String KEY_EXTRAS = "extras";
    private EditText msgText;


注册消息接收和设置自定义消息


public void registerMessageReceiver() {
        mMessageReceiver = new MessageReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(MESSAGE_RECEIVED_ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter);
    }
    public class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {
                    String messge = intent.getStringExtra(KEY_MESSAGE);
                    String extras = intent.getStringExtra(KEY_EXTRAS);
                    StringBuilder showMsg = new StringBuilder();
                    showMsg.append(KEY_MESSAGE + " : " + messge + "\n");
                    if (!ExampleUtil.isEmpty(extras)) {
                        showMsg.append(KEY_EXTRAS + " : " + extras + "\n");
                    }
                    setCostomMsg(showMsg.toString());
                }
            } catch (Exception e){
            }
        }
    }
    //设置自定义消息
    private void setCostomMsg(String msg){
        if (null != msgText) {
            msgText.setText(msg);
            msgText.setVisibility(View.VISIBLE);
        }
    }


然后在onCreate中初始化和调用


    JPushInterface.init(getApplicationContext());//极光接口初始化,否则用不了
        registerMessageReceiver();//注册消息接收器


现在你就可以运行了

20200518174434364.png

⑥ 发送通知


很好,看到Hello World!了,现在打开极光的控制台


20200518174615174.png


点击进入

20200518174728537.png


因为我已经安装了应用,所以在平台上可以看到新增了一个用户。

设置推送消息

20200518174929337.png


滑动到最下面,广播所有人的意思就是只要是安装了这个应用的人都会收到通知

20200518175045563.png


然后预览

20200518175207419.png


然后你会看到预估人数1,就算你这里是0也没有关系,因为这个平台的数据有时候会有延时,不用担心,大胆的勇敢的点击确认发送通知吧!


20200518175331417.png


发送成功!

而且手机上也收到了通知了

20200518175502102.png

⑦ 点击通知跳转页面


在使用其他的APP的时候点击通知的时候通常会打开不同的页面或者不同的URL,而目前你要是点击这个通知的话就是重新打开当前应用,这显然不是那么的合理,所以当我们需要点击通知跳转到不同页面时,要怎么做呢?


这个方面的功能极光中并没有详细说明,我也是经过反复测试和摸索才总结出来的,回到PushReceiver,在这里之前只做了一个简单的继承,而且是也是在这里做通知点击之后的业务处理的。


因此我需要重写onNotifyMessageOpened方法。它是一个通知栏点击的监听,我只要在点击的时候跳转到其他页面就行了,非常的简单吧。


不过呢?首先需要新建一个页面才行,就取名TestActivity。


20201204102340539.png


然后进入到PushReceiver


package com.llw.pushdemo.receiver;
import android.content.Context;
import android.content.Intent;
import com.llw.pushdemo.TestActivity;
import cn.jpush.android.api.NotificationMessage;
import cn.jpush.android.service.JPushMessageReceiver;
public class PushReceiver extends JPushMessageReceiver {
    @Override
    public void onNotifyMessageOpened(Context context, NotificationMessage notificationMessage) {
        Intent intent = new Intent(context, TestActivity.class);
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP );
        context.startActivity(intent);
    }
}


很简单的代码对不对,就是跳转页面而已。


下面直接运行吧,通过极光平台发送通知,App收到通知,然后点击通知栏。

20201204105123447.gif


这样它就可以跳转到TestActivity页面了。而如果你要携带一些参数呢?

也很简单,


20201204105311807.png


在极光平台上发送通知的时候,配置附加字段。然后回到PushReceiver


20201204105436924.png


然后修改一些activity_test.xml


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:orientation="vertical"
    tools:context=".TestActivity">
    <TextView
      android:id="@+id/tv_test"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="#000"
        android:textSize="20sp" />
</LinearLayout>


然后在TestActivity中


package com.llw.pushdemo;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class TestActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_test);
        TextView tvTest = findViewById(R.id.tv_test);
        String extras = getIntent().getStringExtra("extras");
        if(extras !=null){
            tvTest.setText(extras);
        }
    }
}


代码也很简单,通过getIntent拿到传递过来的数据,然后显示在TextView上,下面来试试吧。

20201204113554562.gif


OK,内容就有了。


⑧ 拓展 应用通知开关监听


你看,就这样实现了。你以为就完了吗?


20200518175612474.png


当然没有完!注意到上面的图是推送消息的记录,目标1,成功1,当然有的手机会收不到通知,这是为什么呢?因为国内的很多手机厂商对Android系统进行了自家系统开发,导致,Android的兼容比较难做,因为有的手机默认应用就不允许接收通知,所以你收不到也不要觉得奇怪,在手机设置里打开通知开关就可以了。


我的是荣耀 20i,默认安装应用就自动打开了这个开关的。


这里就涉及到另一个知识点了,那就是通知开关的监听。举个例子,爱奇艺APP,平时老是给我推送通知,烦得很,然后我就给它关了通知,下次进入APP是会有一个提示


2020051818052296.png


就像这样,基本每个成熟的APP,都会有这个监听的。下面来看看怎么做吧。

无非就是两个方法而已


//是否开启通知接收
private boolean isNotificationEnabled(Context context) {
        boolean isOpened = false;
        try {
            isOpened = NotificationManagerCompat.from(context).areNotificationsEnabled();
        } catch (Exception e) {
            e.printStackTrace();
            isOpened = false;
        }
        return isOpened;
    }
  //去设置
    private void gotoSet() {
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= 26) {
            // android 8.0引导
            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());
        } else if (Build.VERSION.SDK_INT >= 21) {
            // android 5.0-7.0
            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            intent.putExtra("app_package", getPackageName());
            intent.putExtra("app_uid", getApplicationInfo().uid);
        } else {
            // 其他
            intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
            intent.setData(Uri.fromParts("package", getPackageName(), null));
        }
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }


然后就是使用方法了

20200518180822886.png


这个时候如果你的这个Demo通知是关闭的话,那么你一打开这个页面就会跳转到通知开启那里去。OK,你以为完了吗?

真的完了!

最后贴一下MainActiviy.java的完整代码


package com.llw.pushdemo;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.NotificationManagerCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.view.View;
import android.widget.EditText;
import cn.jpush.android.api.JPushInterface;
public class MainActivity extends AppCompatActivity {
    //for receive customer msg from jpush server
    private MessageReceiver mMessageReceiver;
    public static final String MESSAGE_RECEIVED_ACTION = "com.example.jpushdemo.MESSAGE_RECEIVED_ACTION";
    public static final String KEY_TITLE = "title";
    public static final String KEY_MESSAGE = "message";
    public static final String KEY_EXTRAS = "extras";
    private EditText msgText;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        JPushInterface.init(getApplicationContext());//极光接口初始化,否则用不了
        registerMessageReceiver();//注册消息接收器
        //判断该app是否打开了通知,如果没有的话就打开手机设置页面
        if (!isNotificationEnabled(this)) {
            //开启通知弹窗
            gotoSet();
        } else {
            //当前app允许消息通知
        }
    }
    public void registerMessageReceiver() {
        mMessageReceiver = new MessageReceiver();
        IntentFilter filter = new IntentFilter();
        filter.setPriority(IntentFilter.SYSTEM_HIGH_PRIORITY);
        filter.addAction(MESSAGE_RECEIVED_ACTION);
        LocalBroadcastManager.getInstance(this).registerReceiver(mMessageReceiver, filter);
    }
    public class MessageReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            try {
                if (MESSAGE_RECEIVED_ACTION.equals(intent.getAction())) {
                    String messge = intent.getStringExtra(KEY_MESSAGE);
                    String extras = intent.getStringExtra(KEY_EXTRAS);
                    StringBuilder showMsg = new StringBuilder();
                    showMsg.append(KEY_MESSAGE + " : " + messge + "\n");
                    if (!ExampleUtil.isEmpty(extras)) {
                        showMsg.append(KEY_EXTRAS + " : " + extras + "\n");
                    }
                    setCostomMsg(showMsg.toString());
                }
            } catch (Exception e){
            }
        }
    }
    //设置自定义消息
    private void setCostomMsg(String msg){
        if (null != msgText) {
            msgText.setText(msg);
            msgText.setVisibility(View.VISIBLE);
        }
    }
    //是否开启通知接收
    private boolean isNotificationEnabled(Context context) {
        boolean isOpened = false;
        try {
            isOpened = NotificationManagerCompat.from(context).areNotificationsEnabled();
        } catch (Exception e) {
            e.printStackTrace();
            isOpened = false;
        }
        return isOpened;
    }
    //去设置
    private void gotoSet() {
        Intent intent = new Intent();
        if (Build.VERSION.SDK_INT >= 26) {
            // android 8.0引导
            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            intent.putExtra("android.provider.extra.APP_PACKAGE", getPackageName());
        } else if (Build.VERSION.SDK_INT >= 21) {
            // android 5.0-7.0
            intent.setAction("android.settings.APP_NOTIFICATION_SETTINGS");
            intent.putExtra("app_package", getPackageName());
            intent.putExtra("app_uid", getApplicationInfo().uid);
        } else {
            // 其他
            intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
            intent.setData(Uri.fromParts("package", getPackageName(), null));
        }
        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        startActivity(intent);
    }
}


⑨ 源码

相关文章
|
9月前
|
定位技术 API 开发工具
Android 按照步骤接入百度地图API,定位显示不了解决办法
Android 按照步骤接入百度地图API,定位显示不了解决办法
252 0
|
20天前
|
API Android开发
Android Framework增加API 报错 Missing nullability on parameter
Android Framework增加API 报错 Missing nullability on parameter
11 1
|
8月前
|
API Android开发
mPaaS(移动跨平台框架)目前已经支持了Android API级别21
mPaaS(移动跨平台框架)目前已经支持了Android API级别21
108 2
|
9月前
|
API 数据库 Android开发
Android SQLite数据库中基础的增删改查操作以及API的详解
Android SQLite数据库中基础的增删改查操作以及API的详解
67 0
|
9月前
|
存储 前端开发 Java
极光推送REST API与Java后台对接
极光推送REST API与Java后台对接
165 0
|
11月前
|
API Android开发
Android Activity Result API
Android Activity Result API
103 0
|
12月前
|
Java API Android开发
Sui为根应用提供Java APIs,滴API。主要提供直接使用Android APIs的能力(几乎以Java作为root的身份
Sui为根应用提供Java APIs,滴API。主要提供直接使用Android APIs的能力(几乎以Java作为root的身份,在root下启动app自己的AIDL风格的Java服务。这将使root应用程序开发变得更加容易。
143 0
|
缓存 Java API
Android音频API
MediaRecorder与MediaPlayer并不能算完整意义的音频API,它们只是系统音频API的封装,除了采集/播放,他们集成了编码/解码、复用/解复用等能力。它们在最底层还是调用了AudioRecorder、AudioTrack。下面主要介绍它们的几个主要的配置项。
370 0
|
Ubuntu Java Shell
Android使用FFmpeg的API库
Android使用FFmpeg的API库
299 1
|
定位技术 API Android开发
Android Studio进行APP设计调用百度地图API接口隐藏百度地图的logo方法
Android Studio进行APP设计调用百度地图API接口隐藏百度地图的logo方法
319 0
Android Studio进行APP设计调用百度地图API接口隐藏百度地图的logo方法