手把手教你集成环信ReactNative离线推送

news2024/11/23 4:09:10

前言:在集成ReactNative推送之前,需要了解ReactNative与Android原生交互

一、RN与Android原生交互

RN给原生传递参数

步骤:

1.用Android Studio打开一个已经存在的RN项目,即用AS打开 项目文件夹/android,如下图所示
在这里插入图片描述
在这里插入图片描述

2.在Android原生这边创建一个类继承ReactContextBaseJavaModule,这个类里边放我们需要被RN调用的方法,将其封装成一个原生模块。
在这里插入图片描述
在这里插入图片描述

MyNativeModule.java代码如下:

package com.awesomeproject;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.xiaomi.mipush.sdk.MiPushClient;
import org.json.JSONException;
import org.json.JSONObject;

public class PushModule extends ReactContextBaseJavaModule {
    private ReactApplicationContext reactContext;
    public PushModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Override
    public String getName() {
        return "PushModule";
    }
    /**
     从RN界面里面调用该方法
     **/
    @ReactMethod
    public void getDeviceToken(){
        MainApplication.getReactPackage().mModule.sendDataToJS( MiPushClient.getRegId(MainApplication.getContext()));


    }
    
    public void sendDataToJS(String deviceToken){
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("deviceToken",deviceToken);
            jsonObject.put("deviceName","");

        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("deviceToken",jsonObject.toString());
    }



}

本类中存放我们要复用的原生方法,继承了ReactContextBaseJavaModule类,并且实现了其getName()方法,构造方法也是必须的。按着Alt+Enter程序会自动提示。接着定义了一个方法,该方法必须使用注解@ReactMethod标明,说明是RN要调用的方法。

3.在Android原生这边创建一个类实现接口ReactPackage包管理器,并把第二步创建的类加到原生模块(NativeModule)列表里。

在这里插入图片描述

PushPackage.java代码如下:


package com.awesomeproject;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class PushPackage implements ReactPackage {
    public PushModule mModule;
    @Override
    public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
        List<NativeModule> list = new ArrayList<>();
        mModule = new PushModule(reactContext);
        list.add(mModule);
        return list;
    }

    @Override
    public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
        return Collections.emptyList();
    }
}

4.将第三步创建的包管理器添加到ReactPackage列表里(getPackage方法里)

MainApplication.java代码如下:


package com.awesomeproject;

import android.app.Application;
import android.content.Context;
import android.util.Log;

import com.facebook.react.PackageList;
import com.facebook.react.ReactApplication;
import com.facebook.react.ReactInstanceManager;
import com.facebook.react.ReactNativeHost;
import com.facebook.react.ReactPackage;
import com.facebook.react.config.ReactFeatureFlags;
import com.facebook.soloader.SoLoader;
import com.awesomeproject.newarchitecture.MainApplicationReactNativeHost;
import com.vivo.push.IPushActionListener;
import com.vivo.push.PushClient;
import com.vivo.push.PushConfig;
import com.vivo.push.util.VivoPushException;
import com.xiaomi.channel.commonutils.logger.LoggerInterface;
import com.xiaomi.mipush.sdk.Logger;
import com.xiaomi.mipush.sdk.MiPushClient;

import java.lang.reflect.InvocationTargetException;
import java.util.List;

public class MainApplication extends Application implements ReactApplication {

  private final ReactNativeHost mReactNativeHost =
      new ReactNativeHost(this) {
        @Override
        public boolean getUseDeveloperSupport() {
          return BuildConfig.DEBUG;
        }

        @Override
        protected List<ReactPackage> getPackages() {
          @SuppressWarnings("UnnecessaryLocalVariable")
          List<ReactPackage> packages = new PackageList(this).getPackages();
          packages.add(mCommPackage);
          // Packages that cannot be autolinked yet can be added manually here, for example:
          // packages.add(new MyReactNativePackage());
          return packages;
        }

        @Override
        protected String getJSMainModuleName() {
          return "index";
        }
      };

  private final ReactNativeHost mNewArchitectureNativeHost =
      new MainApplicationReactNativeHost(this);

  @Override
  public ReactNativeHost getReactNativeHost() {
    if (BuildConfig.IS_NEW_ARCHITECTURE_ENABLED) {
      return mNewArchitectureNativeHost;
    } else {
      return mReactNativeHost;
    }
  }


    static Context context;

    public static Context getContext() {
        return context;
    }
    private static final PushPackage mCommPackage = new PushPackage();
    public static PushPackage getReactPackage() {
        return mCommPackage;
    }



    @Override
  public void onCreate() {
    super.onCreate();
        context = this;
    // If you opted-in for the New Architecture, we enable the TurboModule system
    ReactFeatureFlags.useTurboModules = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
    SoLoader.init(this, /* native exopackage */ false);
    initializeFlipper(this, getReactNativeHost().getReactInstanceManager());



        //初始化push

        try {
//PushConfig.agreePrivacyStatement属性及含义说明请参考接口文档
//使用方法
            PushConfig config = new PushConfig.Builder()
                    .agreePrivacyStatement(true)
                    .build();
            PushClient.getInstance(MainApplication.this).initialize(config);
        } catch (VivoPushException e) {
            Log.d("VivoPushException","-------------"+e.toString());
//此处异常说明是有必须的vpush配置未配置所致,需要仔细检查集成指南的各项配置。
            e.printStackTrace();
        }



// 打开push开关, 关闭为turnOffPush,详见api接入文档
        PushClient.getInstance(this).turnOnPush(new IPushActionListener() {
            @Override
            public void onStateChanged(int state) {
                // TODO: 开关状态处理, 0代表成功,获取regid建议在state=0后获取;
                Log.d("vivo初始化------","开关状态处理, 0代表成功,获取regid建议在state=0后获取----"+state);
            }
        });


        //小米初始化push推送服务

        MiPushClient.registerPush(this, "2882303761517520571", "5841752092571");

        //打开Log
        LoggerInterface newLogger = new LoggerInterface() {

            @Override
            public void setTag(String tag) {
                Log.d("MainApplication-------",tag);
                // ignore
            }

            @Override
            public void log(String content, Throwable t) {
                Log.d("MainApplication-------",content+"-----"+t.toString());

            }

            @Override
            public void log(String content) {
                Log.d("MainApplication-------",content);
            }
        };
        Logger.setLogger(this, newLogger);
  }

  /**
   * Loads Flipper in React Native templates. Call this in the onCreate method with something like
   * initializeFlipper(this, getReactNativeHost().getReactInstanceManager());
   *
   * @param context
   * @param reactInstanceManager
   */
  private static void initializeFlipper(
      Context context, ReactInstanceManager reactInstanceManager) {
    if (BuildConfig.DEBUG) {
      try {
        /*
         We use reflection here to pick up the class that initializes Flipper,
        since Flipper library is not available in release mode
        */
        Class<?> aClass = Class.forName("com.awesomeproject.ReactNativeFlipper");
        aClass
            .getMethod("initializeFlipper", Context.class, ReactInstanceManager.class)
            .invoke(null, context, reactInstanceManager);
      } catch (ClassNotFoundException e) {
        e.printStackTrace();
      } catch (NoSuchMethodException e) {
        e.printStackTrace();
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        e.printStackTrace();
      }
    }
  }

}

5.在RN中去调用原生模块,必须import NativeModule模块。
修改App.js文件,需要从‘react-native’中引用‘NativeModules’,
App.js代码如下:

NativeModules.PushModule.getDeviceToken();

来分析一下程序运行流程:
(1)在配置文件AndroidManifest.xml中,android:name=“.MainApplication”,则MainApplication.java会执行。
(2)在MainApplication.java中,有我们创建的包管理器对象。程序加入PushPackage.java中。
(3)在PushPackage.java中,将我们自己创建的模块加入了原生模块列表中,程序进入PushModule.java中。
(4)在PushModule.java中,提供RN 调用的方法getDeviceToken

实现数据从Android原生回调到RN前端界面

我们都知道,要被RN调用的方法必须是void 类型,即没有返回值,但是项目中很多地方都需要返回数据。那怎么实现呢?

步骤:
1.在Android原生这边创建一个类继承ReactContextBaseJavaModule,这个类里边放我们需要被RN调用的方法,将其封装成一个原生模块。
在上面的PushModule中已经继承了ReactContextBaseJavaModule
我们需要调用sendDataToJS将数据传到RN 层。
PushModule.java 代码如下


package com.awesomeproject;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.xiaomi.mipush.sdk.MiPushClient;
import org.json.JSONException;
import org.json.JSONObject;

public class PushModule extends ReactContextBaseJavaModule {
    private ReactApplicationContext reactContext;
    public PushModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Override
    public String getName() {
        return "PushModule";
    }
    /**
     从RN界面里面调用该方法
     **/
    @ReactMethod
    public void getDeviceToken(){
        MainApplication.getReactPackage().mModule.sendDataToJS( MiPushClient.getRegId(MainApplication.getContext()));


    }

    public void sendDataToJS(String deviceToken){
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("deviceToken",deviceToken);
            jsonObject.put("deviceName","2882303761517520571");

        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("deviceToken",jsonObject.toString());
    }



}

步骤
1、在RN 中调用原生的方法


NativeModules.PushModule.getDeviceToken();

2、原生提供对应的方法,将数据传递
在这里插入图片描述

3、RN 接收原生传递的数据
在这里插入图片描述

至此,我们实现了RN复用原生代码,即将原生模块封装成一个接口,在RN中调用。并且可以封装更加复杂的方法,同时实现了数据回调,即将数据从原生模块中传递到RN前端。

二、原生获取设备信息和ReactNative进行绑定信息

本文介绍如何如何从原生获取推送所需要的设备信息以及ReactNative 绑定信息

前提条件
集成环信即时通讯 React-Native,并且可以正常运行,初始化以及登录
集成文档见环信官网:https://docs-im-beta.easemob.com/document/react-native/quickstart.html

原生获取设备信息:

华为:
在获取华为推送token 之前,我们需要先集成华为sdk,可以参考华为官网官网的集成,也可以参考环信官网进行集成;
获取推送token 参考华为官网文档
获取代码如下:

private void getToken() {
    // 创建一个新线程
    new Thread() {
        @Override
        public void run() {
            try {
                // 从agconnect-services.json文件中读取APP_ID
                String appId = "your APP_ID";

                // 输入token标识"HCM"
                String tokenScope = "HCM";
                String token = HmsInstanceId.getInstance(MainActivity.this).getToken(appId, tokenScope);
                Log.i(TAG, "get token: " + token);
                
                // 判断token是否为空
                if(!TextUtils.isEmpty(token)) {
                    sendRegTokenToServer(token);
                }
            } catch (ApiException e) {
                Log.e(TAG, "get token failed, " + e);
            }
        }
    }.start();
}
private void sendRegTokenToServer(String token) {
    Log.i(TAG, "sending token to server. token:" + token);
}

华为官网有详细的集成介绍,可以仔细阅读, getToken() 方法获取到的就是推送所需要的token。

小米:

1. 前提条件
您已启用推送服务,并获得应用的AppId、AppKey和AppSecret。
2. 接入准备

  1. 下载MiPush Android客户端SDK软件包
    MiPush Android客户端SDK从5.0.1版本开始,提供AAR包接入方式,其支持的最低Android SDK版本为19。
    下载地址:https://admin.xmpush.xiaomi.com/zh_CN/mipush/downpage
    建议您下载最新版本。

  2. 如您之前通过JAR包方式接入过MiPush客户端SDK,需将原JAR包接入配置完全删除,具体配置请参见《Android客户端SDK集成指南(JAR版)》。

  3. 接入指导
    添加依赖
    首先将MiPush SDK的AAR包如MiPush_SDK_Client_xxx.aar 复制到项目/libs/目录,然后在项目APP module的build.gradle中依赖:

android{
    repositories {
        flatDir {
            dirs 'libs'
        }
    }
}
dependencies {
    implementation (name: 'MiPush_SDK_Client_xxx', ext: 'aar')
}

然后需要把该自定义BroadcastReceiver注册到AndroidManifest.xml文件中,注册内容如下:

<receiver
  android:exported="true"
  android:name="com.xiaomi.mipushdemo.DemoMessageReceiver">
          <!--这里com.xiaomi.mipushdemo.DemoMessageRreceiver改成app中定义的完整类名-->
  <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>

注意:请务必确保该自定义BroadcastReceiver所在进程与调用注册推送接口(MiPushClient.registerPush())的进程为同一进程(强烈建议都在主进程中)。

注册推送服务
通过调用MiPushClient.registerPush来初始化小米推送服务。注册成功后,您可以在自定义的onCommandResult和onReceiveRegisterResult中收到注册结果,其中的regId即是当前设备上当前app的唯一标示。您可以将regId上传到自己的服务器,方便向其发消息。
为了提高push的注册率,您可以在Application的onCreate中初始化push。您也可以根据需要,在其他地方初始化push。 代码如下:


public class DemoApplication extends Application {

    public static final String APP_ID = "your appid";
    public static final String APP_KEY = "your appkey";
    public static final String TAG = "your packagename";

    @Override
    public void onCreate() {
        super.onCreate();
        //初始化push推送服务
        if(shouldInit()) {
            MiPushClient.registerPush(this, APP_ID, APP_KEY);
        }
        //打开Log
        LoggerInterface newLogger = new LoggerInterface() {

            @Override
            public void setTag(String tag) {
                // ignore   
            }

            @Override
            public void log(String content, Throwable t) {
                Log.d(TAG, content, t);
            }

            @Override
            public void log(String content) {
                Log.d(TAG, content);
            }
        };
        Logger.setLogger(this, newLogger);
    }

    private boolean shouldInit() {
        ActivityManager am = ((ActivityManager) getSystemService(Context.ACTIVITY_SERVICE));
        List<RunningAppProcessInfo> processInfos = am.getRunningAppProcesses();
        String mainProcessName = getApplicationInfo().processName;
        int myPid = Process.myPid();
        for (RunningAppProcessInfo info : processInfos) {
            if (info.pid == myPid && mainProcessName.equals(info.processName)) {
                return true;
            }
        }
        return false;
    }
}

最后获取推送token,代码如下


 MiPushClient.getRegId(MainApplication.getContext())

vivo:
vivo sdk 下载地址:https://swsdl.vivo.com.cn/appstore/developer/uploadFile/20230602/qrmgtt/vivopushsdk_3.0.0.7_488.rar

一、集成sdk
1. 导入aar 包
将解压后的libs文件夹中vivopushsdk-VERSION.aar(vivopushsdk-VERSION.aar为集成的jar包名字,VERSION为版本名称)拷贝到您的工程的libs文件夹中。
在android项目app目录下的build.gradle中添加aar依赖。


dependencies {
 implementation fileTree(include: ['*.jar'],   dir: 'libs')

 implementation   files("libs/vivo_pushSDK_v3.0.0.7_488.aar")
}

2. 添加权限
vivo Push集成只需要配置网络权限,请在当前工程AndroidManifest.xml中的manifest节点下添加以下代码:

<!Vivo Push需要的权限--> 

<uses-permission  android:name="android.permission.INTERNET"/>

3. 配置appid 、api key等信息
vivo Push集成需要配置对应的appid 、app key信息,其中appid 和app key是在开发者平台中申请的,详见 vivo push 操作手册。
请在当前工程AndroidManifest.xml中的Application节点下添加以下代码(建议复制粘贴防止出错):


<!--Vivo Push开放平台中应用的appid 和api key--> 
<meta-data 
   android:name="api_key" 
   android:value="xxxxxxxx"/> 

<meta-data 
   android:name="app_id" 
   android:value="xxxx"/>

4. 自定义通知回调类
在当前工程中新建一个类 PushMessageReceiverImpl(自定义类名)继承OpenClientPushMessageReceiver 并重载实现相关方法。并在当前工程的AndroidManifest.xml文件中,添加自定义Receiver信息,代码如下:

<!--push应用定义消息receiver声明--> 
<receiver android:name="xxx.xxx.xxx.PushMessageReceiverImpl(自定义类名)" 
   android:exported="false">    
<intent-filter> 
    <!--接收push消息--> 
   <action android:name="com.vivo.pushclient.action.RECEIVE"/> 
</intent-filter>
</receiver>

5. 注册service
接入SDK,需注册相关服务以确保正常。
请在当前工程AndroidManifest.xml中的Application节点下添加以下代码(建议复制粘贴防止出错):


<!--Vivo Push需要配置的service、activity--> 
<service 
   android:name="com.vivo.push.sdk.service.CommandClientService" 
   android:permission="com.push.permission.UPSTAGESERVICE"
   android:exported="true"/>

6. 配置sdk版本信息(仅通过jar包集成方式需要配置,通过aar包集成无需配置)
通过jar包方式接入SDK,需配置SDK版本信息确保正常。
请在当前工程AndroidManifest.xml中的Application节点下添加以下代码(建议复制粘贴防止出错):


<!--Vivo Push SDK的版本信息--> 
<meta-data 
   android:name="sdk_version_vivo" 
   android:value="488"/>

二、启动推送

在工程的Application中,添加以下代码,用来启动打开push开关,成功后即可在通知消息到达时收到通知。
//在当前工程入口函数,建议在Application的onCreate函数中,在获取用户的同意后,添加以下代码:

//初始化push
try {
//PushConfig.agreePrivacyStatement属性及含义说明请参考接口文档
//使用方法
 PushConfig config = new PushConfig.Builder()
                .agreePrivacyStatement(true/false)
                .build();
PushClient.getInstance(this).initialize(config);
} catch (VivoPushException e) {
//此处异常说明是有必须的vpush配置未配置所致,需要仔细检查集成指南的各项配置。
    e.printStackTrace();
}

// 打开push开关, 关闭为turnOffPush,详见api接入文档
PushClient.getInstance(getApplicationContext()).turnOnPush(new IPushActionListener() { 
    @Override
    public void onStateChanged(int state) { 
       // TODO: 开关状态处理, 0代表成功,获取regid建议在state=0后获取;
    } 
});

三、获取token


即获取regId,使用getRegId() 函数获取参考如下:
PushClient.getInstance(context).getRegId(new IPushQueryActionListener() {
  @Override
  public void onSuccess(String regid) {
  //获取成功,回调参数即是当前应用的regid;                               
  }

  @Override
  public void onFail(Integer errerCode) {
 //获取失败,可以结合错误码参考查询失败原因;
  }});Api 接口 turnOnPush回调成功之后,即可获取到注册id。

注:详情及别的功能见vivo 官网文档:https://dev.vivo.com.cn/documentCenter/doc/365

oppo:

SDK集成步骤
注册并下载SDK
Android的SDK以aar形式提供,第三方APP只需要添加少量代码即可接入OPPO推送服务。
代码参考demo下载:heytapPushDemo
下载aar文件,即3.1.0版本sdk:com.heytap.msp_3.1.0.aar

aar依赖
第一步:添加maven仓库


repositories {
    google()
    mavenCentral()
}

第二步:添加maven依赖


implementation(name: 'com.heytap.msp_3.1.0', ext: 'aar')
//以下依赖都需要添加
implementation 'com.google.code.gson:gson:2.6.2'
implementation 'commons-codec:commons-codec:1.6'
implementation 'com.android.support:support-annotations:28.0.0'(SDK中的接入最小依赖项,也可以参考demo中的依赖)

第三步:添加aar配置
在build文件中添加以下代码


Android{
....

repositories {
    flatDir {
        dirs 'libs'
    }
}

....
}

配置AndroidManifest.xml


1)OPPO推送服务SDK支持的最低安卓版本为Android 4.4系统。
<uses-sdk  android:minSdkVersion="19"/>
 
2)推送服务组件注册
//必须配置
<service
   android:name="com.heytap.msp.push.service.XXXService"    
  android:permission="com.heytap.mcs.permission.SEND_PUSH_MESSAGE"
 android:exported="true">
    <intent-filter>
     <action android:name="com.heytap.mcs.action.RECEIVE_MCS_MESSAGE"/> 
<action android:name="com.heytap.msp.push.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service>(兼容Q版本,继承DataMessageCallbackService)
 
<service
   android:name="com.heytap.msp.push.service.XXXService"     
android:permission="com.coloros.mcs.permission.SEND_MCS_MESSAGE"
android:exported="true">
    <intent-filter>
     <action android:name="com.coloros.mcs.action.RECEIVE_MCS_MESSAGE"/>
    </intent-filter>
</service>(兼容Q以下版本,继承CompatibleDataMessageCallbackService)

注册推送服务
1)应用推荐在Application类主进程中调用HeytapPushManager.init(…)接口,这个方法不是耗时操作,执行之后才能使用推送服务
2)业务需要调用api接口,例如应用内开关开启/关闭,需要调用注册接口之后,才会生效
3)由于不是所有平台都支持MSP PUSH,提供接口HeytapPushManager.isSupportPush()方便应用判断是否支持,支持才能执行后续操作
4)通过调用HeytapPushManager.register(…)进行应用注册,注册成功后,您可以在ICallBackResultService的onRegister回调方法中得到regId,您可以将regId上传到自己的服务器,方便向其发消息。初始化相关参数具体要求参考详细API说明中的初始化部分。
5)为了提高push的注册率,你可以在Application的onCreate中初始化push。你也可以根据需要,在其他地方初始化push。如果第一次注册失败,第二次可以直接调用PushManager.getInstance().getRegister()进行重试,此方法默认会使用第一次传入的参数掉调用注册。
在这里插入图片描述

至此,我们获取到了不同设备的device_token

三、从原生将device_token 传到RN 并且绑定

1、原生调用方法


reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
        .emit("deviceToken",jsonObject.toString());

通过PushModule 类进行传递,PushModule 代码如下:


package com.awesomeproject;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import com.xiaomi.mipush.sdk.MiPushClient;
import org.json.JSONException;
import org.json.JSONObject;

public class PushModule extends ReactContextBaseJavaModule {
    private ReactApplicationContext reactContext;
    public PushModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
    }

    @Override
    public String getName() {
        return "PushModule";
    }
    /**
     从RN界面里面调用该方法
     **/
    @ReactMethod
    public void getDeviceToken(){
        MainApplication.getReactPackage().mModule.sendDataToJS( MiPushClient.getRegId(MainApplication.getContext()));


    }

    public void sendDataToJS(String deviceToken){
        JSONObject jsonObject = new JSONObject();
        try {
            jsonObject.put("deviceToken",deviceToken);
            jsonObject.put("deviceName","2882303761517520571");

        } catch (JSONException e) {
            throw new RuntimeException(e);
        }

        this.reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
                .emit("deviceToken",jsonObject.toString());
    }



}

2、RN 层进行获取数据


NativeModules.PushModule.getDeviceToken();
  DeviceEventEmitter.addListener('deviceToken',(res)=>{
    const goosid = JSON.parse(res);
    deviceToken = goosid.deviceToken;
    manufacturer = goosid.deviceName;
    console.log('React Native界面,收到数据:',goosid);

3、获取到数据后调用环信RN sdk 方法进行绑定

ChatClient.getInstance().updatePushConfig(push);

js 代码如下

// 导入依赖库
import React, { useEffect } from 'react';
import {
  DeviceEventEmitter,
  NativeModules,
  SafeAreaView,
  ScrollView,
  StyleSheet,
  Text,
  TextInput,
  View,
} from 'react-native';
import {
  ChatClient,
  ChatMessage,
  ChatMessageChatType,
  ChatOptions,
  ChatPushConfig,
} from 'react-native-chat-sdk';
// 创建 app
const App = () => {
  // 进行 app 设置
  const title = 'ChatQuickstart';
  var deviceToken='';
  var manufacturer='';
  NativeModules.PushModule.getDeviceToken();
  DeviceEventEmitter.addListener('deviceToken',(res)=>{
    const goosid = JSON.parse(res);
    deviceToken = goosid.deviceToken;
    manufacturer = goosid.deviceName;
    console.log('React Native界面,收到数据:',goosid);

})
  const [appKey, setAppKey] = React.useState('1137220225110285#demo');
  const [username, setUsername] = React.useState('p9');
  const [password, setPassword] = React.useState('1');
  const [userId, setUserId] = React.useState('');
  const [content, setContent] = React.useState('');
  const [logText, setWarnText] = React.useState('Show log area');

  // 输出 console log 文件
  useEffect(() => {
    logText.split('\n').forEach((value, index, array) => {
      if (index === 0) {
        console.log(value);
      }
    });
  }, [logText]);

  // 输出 UI log 文件
  const rollLog = text => {
    setWarnText(preLogText => {
      let newLogText = text;
      preLogText
        .split('\n')
        .filter((value, index, array) => {
          if (index > 8) {
            return false;
          }
          return true;
        })
        .forEach((value, index, array) => {
          newLogText += '\n' + value;
        });
      return newLogText;
    });
  };

  // 设置消息监听器。
  const setMessageListener = () => {
    let msgListener = {
      onMessagesReceived(messages) {
        for (let index = 0; index < messages.length; index++) {
          rollLog('received msgId: ' + messages[index].msgId);
        }
      },
      onCmdMessagesReceived: messages => {},
      onMessagesRead: messages => {},
      onGroupMessageRead: groupMessageAcks => {},
      onMessagesDelivered: messages => {},
      onMessagesRecalled: messages => {},
      onConversationsUpdate: () => {},
      onConversationRead: (from, to) => {},
    };

    ChatClient.getInstance().chatManager.removeAllMessageListener();
    ChatClient.getInstance().chatManager.addMessageListener(msgListener);
  };

  // SDK 初始化。
  // 调用任何接口之前,请先进行初始化。
  const init = () => {
   
    let option = new ChatOptions({
      autoLogin: false,
      appKey: appKey
    });
    ChatClient.getInstance().removeAllConnectionListener();
    ChatClient.getInstance()
      .init(option)
      .then(() => {
        rollLog('init success');
        this.isInitialized = true;
        let listener = {
          onTokenWillExpire() {
            rollLog('token expire.');
          },
          onTokenDidExpire() {
            rollLog('token did expire');
          },
          onConnected() {
            rollLog('login success.');
            setMessageListener();
          },
          onDisconnected(errorCode) {
            rollLog('login fail: ' + errorCode);
          },
        };
        ChatClient.getInstance().addConnectionListener(listener);
      })
      .catch(error => {
        rollLog(
          'init fail: ' +
            (error instanceof Object ? JSON.stringify(error) : error),
        );
      });
  };

  // 注册账号。
  const registerAccount = () => {
    if (this.isInitialized === false || this.isInitialized === undefined) {
      rollLog('Perform initialization first.');
      return;
    }
    rollLog('start register account ...');
    ChatClient.getInstance()
      .createAccount(username, password)
      .then(response => {
        rollLog(`register success: userName = ${username}, password = ******`);
      })
      .catch(error => {
        rollLog('register fail: ' + JSON.stringify(error));
      });
  };

  // 用环信即时通讯 IM 账号和密码登录。
  const loginWithPassword = () => {
    if (this.isInitialized === false || this.isInitialized === undefined) {
      rollLog('Perform initialization first.');
      return;
    }
    rollLog('start login ...');
    ChatClient.getInstance()
      .login(username, password)
      .then(() => {
        rollLog('login operation success.');
        let push = new ChatPushConfig({
          deviceId:manufacturer,
          deviceToken:deviceToken,
          
        });
        console.log("--------------------------------------------");
        console.log(manufacturer);
        console.log(deviceToken);
        console.log("--------------------------------------------");
        ChatClient.getInstance().updatePushConfig(push);
      })
      .catch(reason => {
        rollLog('login fail: ' + JSON.stringify(reason));
      });
  };

  // 登出。
  const logout = () => {
    if (this.isInitialized === false || this.isInitialized === undefined) {
      rollLog('Perform initialization first.');
      return;
    }
    rollLog('start logout ...');
    ChatClient.getInstance()
      .logout()
      .then(() => {
        rollLog('logout success.');
      })
      .catch(reason => {
        rollLog('logout fail:' + JSON.stringify(reason));
      });
  };

  // 发送一条文本消息。
  const sendmsg = () => {
    if (this.isInitialized === false || this.isInitialized === undefined) {
      rollLog('Perform initialization first.');
      return;
    }
    let msg = ChatMessage.createTextMessage(
      userId,
      content,
      ChatMessageChatType.PeerChat,
    );
    const callback = new (class {
      onProgress(locaMsgId, progress) {
        rollLog(`send message process: ${locaMsgId}, ${progress}`);
      }
      onError(locaMsgId, error) {
        rollLog(`send message fail: ${locaMsgId}, ${JSON.stringify(error)}`);
      }
      onSuccess(message) {
        rollLog('send message success: ' + message.localMsgId);
      }
    })();
    rollLog('start send message ...');
    ChatClient.getInstance()
      .chatManager.sendMessage(msg, callback)
      .then(() => {
        rollLog('send message: ' + msg.localMsgId);
      })
      .catch(reason => {
        rollLog('send fail: ' + JSON.stringify(reason));
      });
  };

  // UI 组件渲染。
  return (
    <SafeAreaView>
      <View style={styles.titleContainer}>
        <Text style={styles.title}>{title}</Text>
      </View>
      <ScrollView>
        <View style={styles.inputCon}>
          <TextInput
            multiline
            style={styles.inputBox}
            placeholder="Enter appkey"
            onChangeText={text => setAppKey(text)}
            value={appKey}
          />
        </View>
        <View style={styles.buttonCon}>
          <Text style={styles.btn2} onPress={init}>
            INIT SDK
          </Text>
        </View>
        <View style={styles.inputCon}>
          <TextInput
            multiline
            style={styles.inputBox}
            placeholder="Enter username"
            onChangeText={text => setUsername(text)}
            value={username}
          />
        </View>
        <View style={styles.inputCon}>
          <TextInput
            multiline
            style={styles.inputBox}
            placeholder="Enter password"
            onChangeText={text => setPassword(text)}
            value={password}
          />
        </View>
        <View style={styles.buttonCon}>
          <Text style={styles.eachBtn} onPress={registerAccount}>
            SIGN UP
          </Text>
          <Text style={styles.eachBtn} onPress={loginWithPassword}>
            SIGN IN
          </Text>
          <Text style={styles.eachBtn} onPress={logout}>
            SIGN OUT
          </Text>
        </View>
        <View style={styles.inputCon}>
          <TextInput
            multiline
            style={styles.inputBox}
            placeholder="Enter the username you want to send"
            onChangeText={text => setUserId(text)}
            value={userId}
          />
        </View>
        <View style={styles.inputCon}>
          <TextInput
            multiline
            style={styles.inputBox}
            placeholder="Enter content"
            onChangeText={text => setContent(text)}
            value={content}
          />
        </View>
        <View style={styles.buttonCon}>
          <Text style={styles.btn2} onPress={sendmsg}>
            SEND TEXT
          </Text>
        </View>
        <View>
          <Text style={styles.logText} multiline={true}>
            {logText}
          </Text>
        </View>
        <View>
          <Text style={styles.logText}>{}</Text>
        </View>
        <View>
          <Text style={styles.logText}>{}</Text>
        </View>
      </ScrollView>
    </SafeAreaView>
  );
};

// 设置 UI。
const styles = StyleSheet.create({
  titleContainer: {
    height: 60,
    backgroundColor: '#6200ED',
  },
  title: {
    lineHeight: 60,
    paddingLeft: 15,
    color: '#fff',
    fontSize: 20,
    fontWeight: '700',
  },
  inputCon: {
    marginLeft: '5%',
    width: '90%',
    height: 60,
    paddingBottom: 6,
    borderBottomWidth: 1,
    borderBottomColor: '#ccc',
  },
  inputBox: {
    marginTop: 15,
    width: '100%',
    fontSize: 14,
    fontWeight: 'bold',
  },
  buttonCon: {
    marginLeft: '2%',
    width: '96%',
    flexDirection: 'row',
    marginTop: 20,
    height: 26,
    justifyContent: 'space-around',
    alignItems: 'center',
  },
  eachBtn: {
    height: 40,
    width: '28%',
    lineHeight: 40,
    textAlign: 'center',
    color: '#fff',
    fontSize: 16,
    backgroundColor: '#6200ED',
    borderRadius: 5,
  },
  btn2: {
    height: 40,
    width: '45%',
    lineHeight: 40,
    textAlign: 'center',
    color: '#fff',
    fontSize: 16,
    backgroundColor: '#6200ED',
    borderRadius: 5,
  },
  logText: {
    padding: 10,
    marginTop: 10,
    color: '#ccc',
    fontSize: 14,
    lineHeight: 20,
  },
});

export default App;

注:需要再登录成功以后进行绑定

四、推送测试

1、push测试
如何查看绑定的证书信息:
登录环信console—>即时推送—>找到对应的用户id—>点击查看用户绑定推送证书(如下图)
在这里插入图片描述

如何测试推送
登录环信console—> 即时推送—>填写相关的内容—>发送预览—>确认推送
在这里插入图片描述

收到推送
在这里插入图片描述

2、离线消息测试
登录环信console—> 即时通讯—>用户管理—>找到对应的用户id—>发送rest 消息
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

至此,ReactNative 推送集成完成。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1045347.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何将微信、支付宝、字节等小程序直接迁移到自有app中

简要回顾一下 FinClip Studio 的相关能力&#xff1a; FinClip Studio 是一款强大的小程序云端容器&#xff0c;它可以将小程序嵌入到您的原生 App 中&#xff0c;实现无缝的融合体验。不仅如此&#xff0c;FinClip 还提供了一系列的工具和功能&#xff0c;以简化小程序的开发…

大模型训练之加速篇 -> peft(Lora) -> accelerator -> deepspeed (Zero)

HUGGINFACE PEFT库&#xff1a; 实现LORA&#xff0c; prefix-tuning. prompttuning, AdaLoRA, LLaMA-Adapter训练的库 HUGGINFACE accelerator库&#xff1a; 是一个将pytorch模型迁移到CPU/GPU/Multi-GPUs/TPU/Fp16/bf16模式下训练的一个标准库 DeepSpeed Pytorch的分布式并…

正点原子lwIP学习笔记——TCP协议

1.TCP协议简介 TCP协议&#xff0c;是一种面向连接、可靠的、基于字节流的传输层通信协议。 主要就是要知道&#xff0c;TCP协议是需要连接才可以互发数据的&#xff0c;连接需要三次挥手&#xff0c;而断开连接需要四次挥手。 2.TCP协议报文结构 TCP协议的头部一共有20字节&…

网易一面:Eureka怎么AP?Nacos既CP又AP,怎么实现的?

说在前面 在40岁老架构师 尼恩的读者交流群(50)中&#xff0c;最近有小伙伴拿到了一线互联网企业如网易、微博、阿里、汽车之家、极兔、有赞、希音、百度、滴滴的面试资格&#xff0c;遇到一几个很重要的面试题&#xff1a; Eureka是AP还是CP&#xff1f; 说说其集群数据一致性…

有哪些ai智能写作是永久免费的

无论你是一个自媒体作者&#xff0c;企业家&#xff0c;还是一个博客写手&#xff0c;你都了解创作的挑战。创意和时间常常成为限制因素&#xff0c;而AI智能写作工具则旨在解决这些问题。 这些工具利用先进的自然语言处理技术&#xff0c;可以生成各种类型的文本&#xff0c;包…

Appium+python+unittest搭建UI自动化框架

阅读本小节&#xff0c;需要读者具备如下前提条件&#xff1a; 掌握一种编程语言基础&#xff0c;如java、python等。 掌握一种单元测试框架&#xff0c;如java语言的testng框架、python的unittest框架。 掌握目前主流的UI测试框架&#xff0c;移动端APP测试框架Appium&…

Java中的IO流的缓冲流

不爱生姜不吃醋⭐️ 如果本文有什么错误的话欢迎在评论区中指正 与其明天开始&#xff0c;不如现在行动&#xff01; 文章目录 &#x1f334;IO流体系结构&#x1f334;缓冲流1.提高效率的原理2.缓冲流的类型3.字符缓冲流两个特有方法 &#x1f334;总结 &#x1f334;IO流体系…

如何查阅下载美国物理学会(APS)文献

APS美国物理学会数据库简介&#xff1a; The American Physical Society (APS)成立于1899年&#xff0c;是世界上最具声望的物理学专业学会之一。APS不仅为用户带来今日尖端研究&#xff0c;同时为全球各研究单位提供自1893年以来&#xff0c;在“PHYSICAL REVIEW”上刊载的所…

2020年12月 Python(二级)真题解析#中国电子学会#全国青少年软件编程等级考试

Python编程&#xff08;1~6级&#xff09;全部真题・点这里 一、单选题&#xff08;共25题&#xff0c;每题2分&#xff0c;共50分&#xff09; 第1题 执行以下代码中&#xff0c;输出的结果是&#xff1f;&#xff08; &#xff09; sum0 for i in range(1,10,3):sumsumi p…

88、Redis 的 value 所支持的数据类型(String、List、Set、Zset、Hash)---->Set相关命令

本次讲解要点&#xff1a; ** Set相关命令&#xff1a;是指value中的数据类型** 启动redis服务器&#xff1a; 打开小黑窗&#xff1a; C:\Users\JH>e: E:>cd E:\install\Redis6.0\Redis-x64-6.0.14\bin E:\install\Redis6.0\Redis-x64-6.0.14\bin>redis-server.exe …

智慧能源:引领未来的能源革命

在当今世界&#xff0c;能源问题是一个备受关注的焦点话题。随着全球人口的不断增长和工业化进程的加速&#xff0c;对能源的需求也日益增加&#xff0c;同时&#xff0c;传统的能源资源面临着日益严重的枯竭和环境污染问题。在这一背景下&#xff0c;智慧能源应运而生&#xf…

vite跨域proxy设置与开发、生产环境的接口配置,接口在生产环境下,还能使用proxy代理地址吗

文章目录 vite的proxy开发环境设置如果后端没有提供可以替换的/mis等可替换的后缀的处理办法接口如何区分.env.development开发和.env.production生产环境接口在生产环境下&#xff0c;还能使用proxy代理地址吗&#xff1f; vite的proxy开发环境设置 环境&#xff1a; vite 4…

服务断路器_服务雪崩解决方案之服务隔离

那显而易见&#xff0c;做服务隔离的目的就是避免服务之间相互影响。毕竟谁也不能说自己的微服务百分百可用&#xff0c;如果不做隔离&#xff0c;一旦一个服务出现了问题&#xff0c;整个系统的稳定性都会受到影响&#xff01; 因此&#xff0c;做服务隔离是很有必要的。 什么…

消费者偏移量_consumer_offsets相关解析

1.概述 __consumer_offsets 是 kafka 自行创建的&#xff0c;和普通的 topic 相同。它存在的目的之一就是保存 consumer 提交的位移。 __consumer_offsets 的每条消息格式大致如图所示: 可以想象成一个 KV 格式的消息&#xff0c;key 就是一个三元组&#xff1a;group.idtopi…

成都睿趣科技:抖音开通橱窗带货需要钱吗

随着社交媒体和电子商务的蓬勃发展&#xff0c;抖音作为一种流行的短视频平台&#xff0c;也推出了自己的“抖音橱窗”功能&#xff0c;让内容创作者能够通过视频展示和销售产品&#xff0c;从而实现商业化。那么&#xff0c;抖音橱窗带货是否需要费用呢? 首先&#xff0c;要开…

现代数据架构-湖仓一体

当前的数据架构已经从数据库、数据仓库&#xff0c;发展到了数据湖、湖仓一体架构&#xff0c;本篇文章从头梳理了一下数据行业发展的脉络。 上世纪&#xff0c;最早出现了关系型数据库&#xff0c;也就是DBMS&#xff0c;有商业的Oracle、 IBM的DB2、Sybase、Informix、 微软…

关于坐标的旋转变换和坐标系的旋转变换

不管是坐标的旋转变换还是坐标系下的旋转变换&#xff0c;只和旋转的顺时针和逆时针有关。然坐标系间的顺时针和逆时针是根据当前坐标系在目标坐标系下的相对位置确定。 一。逆时针旋转belta角度的公式 二。顺时针旋转belta角度的公式 三。坐标的旋转变换 1.坐标的旋转变换相…

一文了解企业如何实现文件自动化实时同步

在当今的数字化时代&#xff0c;数据是企业的核心资产&#xff0c;也是企业竞争力的重要体现。数据的传输、共享、协作、备份等都需要依赖文件同步技术&#xff0c;实现数据在不同平台和设备之间的一致性和可用性。文件同步是指将一个或多个文件夹中的内容复制或更新到另一个或…

网络安全攻防:软件逆向之反汇编

网络安全是当今社会中一个非常重要的问题&#xff0c;而软件逆向工程是网络安全攻防中常用的一种技术手段。在软件逆向工程中&#xff0c;反汇编是一种基础而重要的技术。通过反汇编&#xff0c;我们可以将二进制程序转换为汇编语言&#xff0c;从而更好地理解程序的执行流程和…

在伦敦银投资中,技术是万能的?

一般进行伦敦银投资的投资者都会学习很多技术分析的方法&#xff0c;技术分析是一种还很适合普通投资者使用的市场分析工具&#xff0c;但是在伦敦银投资中&#xff0c;技术分析的作用不是万能的&#xff0c;其实技术分析还是有很多各种各样的缺点&#xff0c;如果投资者迷信技…