2 Android 应用之间通过 GCM 的通信
Communication between 2 Android apps over GCM
我在两台不同的设备上有 2 个 Android 应用程序。 App 1 是固定的,app 2 是移动的。我希望应用程序 1 找到最近的应用程序 2 设备并像 snapchat 一样进行通信,但我想用应用程序 2 的当前位置更新应用程序 1。我将应用程序 1 的位置存储在服务器中并检索应用程序 2 的位置并计算它们之间的距离,然后通过 GCM 将应用程序 1 的位置发送到应用程序 2。但事实证明这比我原先想象的要复杂。我还尝试将移动应用程序的位置存储在数据库中,并在固定请求通信时获取更新的位置,但这意味着数据库更新太多。有人可以提示我如何高效地完成这项工作吗?以下是计算它们之间的距离和发送位置的代码片段。
function distance_slc($lat1, $lon1, $lat2, $lon2) {
global $earth_radius;
global $delta_lat;
global $delta_lon;
$distance = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon));
$distance = acos($distance);
$distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
$distance = round($distance, 4);
return $distance;
}
function compute($id, $lat, $lon) {
$p = getPLocation();
$d = array($id, $lat, $lon);
foreach ($d as $index => $value) {
$d_pass_distance = distance_slc($p['latitude'], $p['longitude'], $d['1'], $d['2']);
$closest_d = 0;
if ($closest_d = min($d_pass_distance)) {
sendPLocation($d['0'], $p['latitude'], $p['longitude']);
}
}
}
function sendUserLocation($id, $lat, $lon) {
//request url
//$url = 'https://android.googleapis.com/gcm/send';
$url = 'gcm-preprod.googleapis.com:5236'; //this url is only for testing not production
//your api key
$apiKey = 'myserverapikeyhere';
$fields = array('id' => $id, 'latitude' => $lat, 'longitude' => $lon);
//http header
$headers = array('Authorization: key=' . $apiKey,
'Content-Type: application/json');
//curl connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
echo $result;
}
我想到的是,当应用程序 1 客户端想要通信时,它会向您的应用程序服务器发送一条消息。然后,应用服务器向所有适当的移动设备发送 GCM 推送消息,每个设备上的应用 2 客户端接收消息,确定其当前位置,并使用上游消息将其位置发送到应用服务器。应用程序服务器确定最近的设备(可能需要等待几秒钟才能获得所有各种响应),然后将推送消息发送到最近的应用程序 2 客户端(以及可选的应用程序 1 客户端),并提供适当的信息。
编辑:包括一些上游和下游消息的示例代码。总的来说,我排除了一般消息传递的东西。您可以用自己的东西替换 "contents" 和 "username" 字段,并且需要有不同类型的上游消息
下游消息(应用服务器端 - 在 Java 中)
public void actionPerformed(ActionEvent e) {
// who are we sending it to?
String toAddr = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
// create the message
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", toAddr);
message.put("message_id", myNextMessageId());
HashMap<String, String> dataPayload = new HashMap<>();
dataPayload.put( "contents", dataInfo.getText() );
message.put("data", dataPayload);
// actually send the message
try {
Packet request = new GcmPacketExtension(JSONValue.toJSONString(message)).toPacket();
connection.sendPacket(request);
} catch ( NotConnectedException enc ) {
// quietly ignore the error
}
}
下游消息(Android 客户端)
public class MyGcmListenerService extends GcmListenerService {
public MyGcmListenerService() { }
public void onMessageReceived (String from, Bundle data) {
// get info ("data" stuff)
String contents = data.getString( "contents" );
... process contents
}
}
上游消息(Android 客户端)
GoogleCloudMessaging gcm;
String SENDER_ID = "999999999999";
// send the registration to the back-end app server
private void sendUpstreamMessage( user ) {
// use upstream message to register with the app server
// app server uses the 'from' field of the message
String msg = "";
try {
Bundle data = new Bundle();
String user = getGoogleAccount();
// username is the user email
data.putString( "username", user );
// and note this is a registration request
data.putString("my_action", "edu.eku.styere.gcmpushclient.REGISTER");
String id = myNewMessageId();
// send the registration message
gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
} catch (IOException ex) {
// for now ignore error
}
return;
}
上游消息(应用服务器 - 在 Java 中再次出现)
// assume we already know this is an upstream message and not an ACK or something else
protected void handleUpstreamMessage(Map<String, Object> jsonObject) {
// PackageName of the application that sent this message.
String category = (String) jsonObject.get("category");
String from = (String) jsonObject.get("from");
@SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
// what action do they want?
String my_action = (String) payload.get( "my_action" );
if ( my_action.equals( "edu.eku.styere.gcmpushclient.REGISTER" ) ) {
// registration request
String username = (String) payload.get( "username" );
registerUser( username, from );
return;
}
}
我在两台不同的设备上有 2 个 Android 应用程序。 App 1 是固定的,app 2 是移动的。我希望应用程序 1 找到最近的应用程序 2 设备并像 snapchat 一样进行通信,但我想用应用程序 2 的当前位置更新应用程序 1。我将应用程序 1 的位置存储在服务器中并检索应用程序 2 的位置并计算它们之间的距离,然后通过 GCM 将应用程序 1 的位置发送到应用程序 2。但事实证明这比我原先想象的要复杂。我还尝试将移动应用程序的位置存储在数据库中,并在固定请求通信时获取更新的位置,但这意味着数据库更新太多。有人可以提示我如何高效地完成这项工作吗?以下是计算它们之间的距离和发送位置的代码片段。
function distance_slc($lat1, $lon1, $lat2, $lon2) {
global $earth_radius;
global $delta_lat;
global $delta_lon;
$distance = sin(deg2rad($lat1)) * sin(deg2rad($lat2)) + cos(deg2rad($lat1)) * cos(deg2rad($lat2)) * cos(deg2rad($delta_lon));
$distance = acos($distance);
$distance = rad2deg($distance);
$distance = $distance * 60 * 1.1515;
$distance = round($distance, 4);
return $distance;
}
function compute($id, $lat, $lon) {
$p = getPLocation();
$d = array($id, $lat, $lon);
foreach ($d as $index => $value) {
$d_pass_distance = distance_slc($p['latitude'], $p['longitude'], $d['1'], $d['2']);
$closest_d = 0;
if ($closest_d = min($d_pass_distance)) {
sendPLocation($d['0'], $p['latitude'], $p['longitude']);
}
}
}
function sendUserLocation($id, $lat, $lon) {
//request url
//$url = 'https://android.googleapis.com/gcm/send';
$url = 'gcm-preprod.googleapis.com:5236'; //this url is only for testing not production
//your api key
$apiKey = 'myserverapikeyhere';
$fields = array('id' => $id, 'latitude' => $lat, 'longitude' => $lon);
//http header
$headers = array('Authorization: key=' . $apiKey,
'Content-Type: application/json');
//curl connection
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($fields));
$result = curl_exec($ch);
curl_close($ch);
echo $result;
}
我想到的是,当应用程序 1 客户端想要通信时,它会向您的应用程序服务器发送一条消息。然后,应用服务器向所有适当的移动设备发送 GCM 推送消息,每个设备上的应用 2 客户端接收消息,确定其当前位置,并使用上游消息将其位置发送到应用服务器。应用程序服务器确定最近的设备(可能需要等待几秒钟才能获得所有各种响应),然后将推送消息发送到最近的应用程序 2 客户端(以及可选的应用程序 1 客户端),并提供适当的信息。
编辑:包括一些上游和下游消息的示例代码。总的来说,我排除了一般消息传递的东西。您可以用自己的东西替换 "contents" 和 "username" 字段,并且需要有不同类型的上游消息
下游消息(应用服务器端 - 在 Java 中)
public void actionPerformed(ActionEvent e) {
// who are we sending it to?
String toAddr = "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz";
// create the message
Map<String, Object> message = new HashMap<String, Object>();
message.put("to", toAddr);
message.put("message_id", myNextMessageId());
HashMap<String, String> dataPayload = new HashMap<>();
dataPayload.put( "contents", dataInfo.getText() );
message.put("data", dataPayload);
// actually send the message
try {
Packet request = new GcmPacketExtension(JSONValue.toJSONString(message)).toPacket();
connection.sendPacket(request);
} catch ( NotConnectedException enc ) {
// quietly ignore the error
}
}
下游消息(Android 客户端)
public class MyGcmListenerService extends GcmListenerService {
public MyGcmListenerService() { }
public void onMessageReceived (String from, Bundle data) {
// get info ("data" stuff)
String contents = data.getString( "contents" );
... process contents
}
}
上游消息(Android 客户端)
GoogleCloudMessaging gcm;
String SENDER_ID = "999999999999";
// send the registration to the back-end app server
private void sendUpstreamMessage( user ) {
// use upstream message to register with the app server
// app server uses the 'from' field of the message
String msg = "";
try {
Bundle data = new Bundle();
String user = getGoogleAccount();
// username is the user email
data.putString( "username", user );
// and note this is a registration request
data.putString("my_action", "edu.eku.styere.gcmpushclient.REGISTER");
String id = myNewMessageId();
// send the registration message
gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);
} catch (IOException ex) {
// for now ignore error
}
return;
}
上游消息(应用服务器 - 在 Java 中再次出现)
// assume we already know this is an upstream message and not an ACK or something else
protected void handleUpstreamMessage(Map<String, Object> jsonObject) {
// PackageName of the application that sent this message.
String category = (String) jsonObject.get("category");
String from = (String) jsonObject.get("from");
@SuppressWarnings("unchecked")
Map<String, String> payload = (Map<String, String>) jsonObject.get("data");
// what action do they want?
String my_action = (String) payload.get( "my_action" );
if ( my_action.equals( "edu.eku.styere.gcmpushclient.REGISTER" ) ) {
// registration request
String username = (String) payload.get( "username" );
registerUser( username, from );
return;
}
}