如何使用firebase消息发送一对一消息

41zrol4v  于 2021-06-30  发布在  Java
关注(0)|答案(5)|浏览(356)

我一直在尝试阅读有关如何从一个设备发送消息到另一个的官方文档和指南。我在实时数据库中保存了两个设备的注册令牌,因此我有另一个设备的注册令牌。我试过以下方法来传递信息

RemoteMessage message = new RemoteMessage.Builder(getRegistrationToken())
                    .setMessageId(incrementIdAndGet())
                    .addData("message", "Hello")
                    .build();
FirebaseMessaging.getInstance().send(message);

然而,这是行不通的。另一个设备没有收到任何消息。我甚至不确定是否可以使用上行消息发送来进行设备到设备的通信。
ps:我只想知道使用fcm是否可以进行设备到设备的消息传递?如果是,那么我使用的代码是否有问题?如果是,那么正确的方法是什么。
更新:
我的问题是,不使用firebase can以外的任何单独服务器的设备到设备的消息传递是否可行,如果可行,那么如何实现,因为没有相关文档。我不明白这里还有什么要解释的?无论如何,我得到了答案,并将更新它作为一个答案,一旦问题重新开放。

guykilcj

guykilcj1#

firebase有两个功能可以向设备发送消息:
firebase控制台中的通知面板允许您向用户订阅的特定设备、用户组或主题发送通知。
通过调用firebase云消息传递api,您可以使用您喜欢的任何目标策略发送消息。调用fcm api需要访问您的服务器密钥,您不应该在客户端设备上公开该密钥。这就是为什么你应该总是在应用服务器上运行这样的代码。
firebase文档直观地显示了这一点:

不支持通过firebase云消息传递将消息从一个设备直接发送到另一个设备。
更新:我写了一篇博客文章,详细介绍了如何使用firebase数据库、云消息和node.js在android设备之间发送通知。
更新2:您现在还可以使用firebase的云功能安全地发送消息,而无需启动服务器。请参阅此示例用例以开始。

esbemjvw

esbemjvw2#

我迟到了,但是上面的解决方案帮助我写下了这个简单的答案,你可以直接把你的信息从android应用程序发送到android设备,这是我做的简单的实现,它对我来说非常有用。
编译android截击库

compile 'com.android.volley:volley:1.0.0'

只需复制粘贴这个简单函数;)你的生活就会变得一帆风顺,就像黄油刀一样d

public static void sendPushToSingleInstance(final Context activity, final HashMap dataValue /*your data from the activity*/, final String instanceIdToken /*firebase instance token you will find in documentation that how to get this*/ ) {

final String url = "https://fcm.googleapis.com/fcm/send";
StringRequest myReq = new StringRequest(Request.Method.POST,url,
        new Response.Listener<String>() {
            @Override
            public void onResponse(String response) {
                Toast.makeText(activity, "Bingo Success", Toast.LENGTH_SHORT).show();
            }
        },
        new Response.ErrorListener() {
            @Override
            public void onErrorResponse(VolleyError error) {
                Toast.makeText(activity, "Oops error", Toast.LENGTH_SHORT).show();
            }
        }) {

    @Override
    public byte[] getBody() throws com.android.volley.AuthFailureError {
        Map<String, Object> rawParameters = new Hashtable();
        rawParameters.put("data", new JSONObject(dataValue));
        rawParameters.put("to", instanceIdToken);
        return new JSONObject(rawParameters).toString().getBytes();
    };

    public String getBodyContentType()
    {
        return "application/json; charset=utf-8";
    }
    @Override
    public Map<String, String> getHeaders() throws AuthFailureError {
        HashMap<String, String> headers = new HashMap<String, String>();
        headers.put("Authorization", "key="+YOUR_LEGACY_SERVER_KEY_FROM_FIREBASE_CONSOLE);
        headers.put("Content-Type","application/json");
        return headers;
    }

};

Volley.newRequestQueue(activity).add(myReq);
}

注意,如果您想向topics发送消息,那么可以将参数instanceidtoken更改为/topics/topicname之类的值。对于组,实现是相同的,但您只需要注意参数。检查firebase文档,您可以传递这些参数。如果您遇到任何问题,请告诉我。

pdsfdshx

pdsfdshx3#

我还在我的原型中使用了直接的设备到设备gcm消息传递。它一直运行得很好。我们没有服务器。我们使用短信/文本交换gcm注册id,然后使用gcm进行通信。我把gcm处理的相关代码放在这里

*发送gcm消息

//Sends gcm message Asynchronously
public class GCM_Sender extends IntentService{
    final String API_KEY = "****************************************";

    //Empty constructor
    public GCM_Sender() {
        super("GCM_Sender");
    }

    //Processes gcm send messages
    @Override
    protected void onHandleIntent(Intent intent) {  

        Log.d("Action Service", "GCM_Sender Service Started");
        //Get message from intent
        String msg = intent.getStringExtra("msg");
        msg =  "\"" + msg + "\"";
        try{
            String ControllerRegistrationId = null;                 
            //Check registration id in db       
            if(RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().size() > 0 ) {
                String controllerRegIdArray[] = RegistrationIdAdapter.getInstance(getApplicationContext()).getRegIds().get(1);
                if(controllerRegIdArray.length>0)
                    ControllerRegistrationId = controllerRegIdArray[controllerRegIdArray.length-1];

                if(!ControllerRegistrationId.equalsIgnoreCase("NULL")){
                    // 1. URL
                    URL url = new URL("https://android.googleapis.com/gcm/send");
                    // 2. Open connection
                    HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
                    // 3. Specify POST method
                    urlConnection.setRequestMethod("POST");
                    // 4. Set the headers
                    urlConnection.setRequestProperty("Content-Type", "application/json");
                    urlConnection.setRequestProperty("Authorization", "key=" + API_KEY);
                    urlConnection.setDoOutput(true);
                    // 5. Add JSON data into POST request body
                    JSONObject obj = new JSONObject("{\"time_to_live\": 0,\"delay_while_idle\": true,\"data\":{\"message\":" + msg + "},\"registration_ids\":[" + ControllerRegistrationId + "]}");
                    // 6. Get connection output stream
                    OutputStreamWriter out = new OutputStreamWriter(urlConnection.getOutputStream());
                    out.write(obj.toString());
                    out.close();
                    // 6. Get the response
                    int responseCode = urlConnection.getResponseCode();

                    BufferedReader in = new BufferedReader(new InputStreamReader(urlConnection.getInputStream()));
                    String inputLine;
                    StringBuffer response = new StringBuffer();
                    while ((inputLine = in.readLine()) != null){
                        response.append(inputLine);
                    }
                    in.close();
                    Log.d("GCM getResponseCode:", new Integer(responseCode).toString());
                }else{
                    Log.d("GCM_Sender:","Field REGISTRATION_TABLE is null");
                }
            }else {
                Log.d("GCM_Sender:","There is no Registration ID in DB ,please sync devices");
            }
        } catch (Exception e) {
            e.printStackTrace();
            //MessageSender.getInstance().sendMessage(msg, Commands.SMS_MESSAGE);
        } 
    }

    //Called when service is no longer alive
    @Override
    public void onDestroy() {
        super.onDestroy();
        //Do a log that GCM_Sender service has been destroyed
        Log.d("Action Service", "GCM_Sender Service Destroyed");
    }
}

*接收gcm消息

public class GCM_Receiver extends WakefulBroadcastReceiver {
    public static final String RETRY_ACTION ="com.google.android.c2dm.intent.RETRY";
    public static final String REGISTRATION ="com.google.android.c2dm.intent.REGISTRATION";
    public SharedPreferences preferences;

    //Processes Gcm message .
    @Override
    public void onReceive(Context context, Intent intent) {
        ComponentName comp = new ComponentName(context.getPackageName(),
                GCMNotificationIntentService.class.getName());
        //Start GCMNotificationIntentService to handle gcm message asynchronously
        startWakefulService(context, (intent.setComponent(comp)));
        setResultCode(Activity.RESULT_OK);

        /*//Check if DatabaseService is running .
        if(!DatabaseService.isServiceRunning) {
            Intent dbService = new Intent(context,DatabaseService.class);
            context.startService(dbService);
        }*/
        //Check if action is RETRY_ACTION ,if it is then do gcm registration again .
        if(intent.getAction().equals(RETRY_ACTION)) {
            String registrationId = intent.getStringExtra("registration_id");

            if(TextUtils.isEmpty(registrationId)){
                DeviceRegistrar.getInstance().register(context);
            }else {
                //Save registration id to prefs .
                preferences = PreferenceManager.getDefaultSharedPreferences(context);
                SharedPreferences.Editor editor = preferences.edit();
                editor.putString("BLACKBOX_REG_ID",registrationId);
                editor.commit();
            }
        } else if (intent.getAction().equals(REGISTRATION)) {
        }

    }
}

//Processes gcm messages asynchronously .
public class GCMNotificationIntentService extends IntentService{
    public static final int NOTIFICATION_ID = 1;
    private NotificationManager mNotificationManager;
    String gcmData;
    private final String TAG = "GCMNotificationIntentService";

    //Constructor with super().
    public GCMNotificationIntentService() {
        super("GcmIntentService");
    }

    //Called when startService() is called by its Client .
    //Processes gcm messages .
    @Override
    protected void onHandleIntent(Intent intent) {

        Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Started");
        Bundle extras = intent.getExtras();
        //Get instance of GoogleCloudMessaging .
        GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
        //Get gcm message type .
        String messageType = gcm.getMessageType(intent);

        if (!extras.isEmpty()) {
            if (GoogleCloudMessaging.MESSAGE_TYPE_SEND_ERROR
                    .equals(messageType)) {
                sendNotification("Send error: " + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_DELETED
                    .equals(messageType)) {
                sendNotification("Deleted messages on server: "
                        + extras.toString());
            } else if (GoogleCloudMessaging.MESSAGE_TYPE_MESSAGE
                    .equals(messageType)) {
                Log.i(TAG, "Completed work @ " + SystemClock.elapsedRealtime());

                gcmData = extras.getString("message");
                Intent actionService = new Intent(getApplicationContext(),Action.class);    
                actionService.putExtra("data", gcmData);
                //start Action service .
                startService(actionService);

                //Show push notification .
                sendNotification("Action: " + gcmData);
                //Process received gcmData.

                Log.d(TAG,"Received Gcm Message from Controller : " + extras.getString("message"));
            }
        }
        GCM_Receiver.completeWakefulIntent(intent);
    }

    //Shows notification on device notification bar .
    private void sendNotification(String msg) {
        mNotificationManager = (NotificationManager) this.getSystemService(Context.NOTIFICATION_SERVICE);
        Intent notificationIntent = new Intent(this, BlackboxStarter.class);
        //Clicking on GCM notification add new layer of app.
        notificationIntent.setFlags( Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        PendingIntent contentIntent = PendingIntent.getActivity(this, 0,notificationIntent, PendingIntent.FLAG_CANCEL_CURRENT);
        NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(
                this).setSmallIcon(R.drawable.gcm_cloud)
                .setContentTitle("Notification from Controller")
                .setStyle(new NotificationCompat.BigTextStyle().bigText(msg))
                .setContentText(msg);
        mBuilder.setContentIntent(contentIntent);
        mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
        //Play default notification
        try {
            Uri notification = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
            Ringtone r = RingtoneManager.getRingtone(getApplicationContext(), notification);
            r.play();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    //Called when service is no longer be available .
    @Override
    public void onDestroy() {
        // TODO Auto-generated method stub
        super.onDestroy();
        Log.d("GCMNotificationIntentService", "GCMNotificationIntentService Destroyed");
    }

}
wecizke3

wecizke34#

警告:有一个非常重要的原因,为什么我们在任何地方都不提及这种方法。这将在每个客户端设备上放置的apk中公开服务器密钥。它可以(因此将)采取从那里,并可能导致滥用您的项目。我强烈建议不要采用这种方法,除非应用程序只能放在自己的设备上弗兰克范帕夫伦
弗兰克的回答是正确的 Firebase 本机不支持设备到设备的消息传递。不过,这里面有一个漏洞。firebase服务器不确定您是从实际服务器发送请求,还是从设备发送请求。
所以你要做的就是发送一个 Post RequestFirebase 的消息服务器以及服务器密钥。请记住,服务器密钥不应该在设备上,但是如果您希望使用firebase消息传递进行设备到设备的消息传递,则没有其他选项。
我使用的是okhttp,而不是调用restapi的默认方式。代码是这样的-

public static final String FCM_MESSAGE_URL = "https://fcm.googleapis.com/fcm/send";
OkHttpClient mClient = new OkHttpClient();
public void sendMessage(final JSONArray recipients, final String title, final String body, final String icon, final String message) {

        new AsyncTask<String, String, String>() {
            @Override
            protected String doInBackground(String... params) {
                try {
                    JSONObject root = new JSONObject();
                    JSONObject notification = new JSONObject();
                    notification.put("body", body);
                    notification.put("title", title);
                    notification.put("icon", icon);

                    JSONObject data = new JSONObject();
                    data.put("message", message);
                    root.put("notification", notification);
                    root.put("data", data);
                    root.put("registration_ids", recipients);

                    String result = postToFCM(root.toString());
                    Log.d(TAG, "Result: " + result);
                    return result;
                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            }

            @Override
            protected void onPostExecute(String result) {
                try {
                    JSONObject resultJson = new JSONObject(result);
                    int success, failure;
                    success = resultJson.getInt("success");
                    failure = resultJson.getInt("failure");
                    Toast.makeText(getCurrentActivity(), "Message Success: " + success + "Message Failed: " + failure, Toast.LENGTH_LONG).show();
                } catch (JSONException e) {
                    e.printStackTrace();
                    Toast.makeText(getCurrentActivity(), "Message Failed, Unknown error occurred.", Toast.LENGTH_LONG).show();
                }
            }
        }.execute();
    }

String postToFCM(String bodyString) throws IOException {
        RequestBody body = RequestBody.create(JSON, bodyString);
        Request request = new Request.Builder()
                .url(FCM_MESSAGE_URL)
                .post(body)
                .addHeader("Authorization", "key=" + SERVER_KEY)
                .build();
        Response response = mClient.newCall(request).execute();
        return response.body().string();
    }

我希望firebase将来会有更好的解决方案。但在那之前,我认为这是唯一的办法。另一种方式是发送主题消息或组消息。但这不在问题的范围之内。
更新:
jsonarray的定义如下-

JSONArray regArray = new JSONArray(regIds);

regids是注册id的字符串数组,您要将此消息发送到。请记住,注册ID必须始终位于一个数组中,即使您希望它发送给单个收件人。

ltqd579y

ltqd579y5#

根据上更新的新文件 October 2, 2018 您必须按以下方式发送邮寄请求

https://fcm.googleapis.com/fcm/send
Content-Type:application/json
Authorization:key=AIzaSyZ-1u...0GBYzPu7Udno5aA //Server key

{
    "to": "sent device's registration token",
    "data": {
       "hello": "message from someone",
    }
}

获取设备的注册令牌 FirebaseMessagingService 和覆盖 onNewToken(String token) 有关更多信息,请参阅文档https://firebase.google.com/docs/cloud-messaging/android/device-group

相关问题