我正在构建一个应用程序来检测Android上的iBeacons。基本功能是将信标发布的数据存储到设备上,并将其上传到服务器。为此,我正在使用 Android Beacon库。
要在Android O上在后台运行它,我正在使用前台服务。问题是,当应用程序在后台运行超过30分钟时,在检测到信标之后,当用户退出信标区域并调用didExitRegion
时,该服务将被自动终止并重新启动,因此没有数据被上传到服务器。同样,在重新启动之后,在第二次didExitRegion
调用中,它会在将来某个时候完全随机地停止,然后重新启动,但要再次执行相同的循环。
应用程序在闲置30分钟左右后进入区域时发生的事件顺序
First Restart after didExit(图片)
在这里,您可以看到从区域11切换到9。Midway应用程序立即关闭并重新触发,但是没有发送推送
Exit after second didExit(图片)
下一步:现在从该区域退出时,应用再次在后台停止。但这一次不会立即重新触发。这是始终发生的确切顺序。
代码段
BeaconScanner.java
@Override
public void didExitRegion(Region region) {
Log.d(TAG, "Exited A Region");
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
notificationHelper.notify(2, notificationHelper.getNotification("BeaconScanner", "Exit Major #"+previousMajor, false));
else
utils.dispatchNotification("Exit Major #"+previousMajor, 1);
Log.e(TAG, "DidSend "+didSend+" has Data "+userData.hasPendingData());
if(didSend && userData.hasPendingData()) {
JSONObject data = userData.getJsonFromUser();
Log.d(TAG, "Timestamp = "+System.currentTimeMillis());
userData.addTimestamp(""+System.currentTimeMillis());
userData.requestDataSync(data);
userData.clearBeaconData();
Log.d(TAG, data.toString());
didSend = !didSend;
}
previousMajor = -1000;
lastBeacon = resetBeacon;
}
User.java
JSONObject getJsonFromUser() {
Log.d(TAG, "Timestamp as in getJsonFromUser "+timestamp);
JSONObject json = new JSONObject();
try {
json.put("email", email);
json.put("name", name);
JSONArray beaconArray = new JSONArray();
for (Beacon beacon : beaconData){
beaconArray.put(new JSONObject()
.put("major", beacon.getId2().toInt())
.put("minor", beacon.getId3().toInt())
.put("uuid", beacon.getId1().toString())
);
}
json.put("data", beaconArray);
Log.d(TAG, timestamp);
json.put("timestamp", ""+System.currentTimeMillis());
return json;
} catch (Exception e){
Log.e(TAG, e.getMessage());
Crashlytics.log(e.getLocalizedMessage());
}
return json;
}
void requestDataSync(final JSONObject json){
User.syncing = true;
Crashlytics.log(1, "User.java", "Requesting Auth Token");
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
user.getIdToken(true).addOnCompleteListener(new OnCompleteListener<GetTokenResult>() {
@Override
public void onComplete(@NonNull Task<GetTokenResult> task) {
if(task.isSuccessful()){
final Task<GetTokenResult> t = task;
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
trustAllHosts();
URL url = new URL("https://indpulse.com/generatetoken");
HttpsURLConnection connection = (HttpsURLConnection) url.openConnection();
connection.setHostnameVerifier(DO_NOT_VERIFY);
connection.setRequestProperty("Authorization", ""+t.getResult().getToken());
connection.setRequestMethod("GET");
Log.d(TAG, t.getResult().getToken());
connection.setDoOutput(true);
connection.connect();
BufferedReader br = new BufferedReader(new InputStreamReader(connection.getInputStream()));
StringBuilder response = new StringBuilder();
String packet;
while((packet = br.readLine()) != null){
response.append(packet);
}
JSONObject responseObject = new JSONObject(response.toString());
String idToken = responseObject.getString("token");
Crashlytics.log(1, "User.java", "Auth Token Acquired");
sendData(json, idToken);
} catch (MalformedURLException e){
Log.e(TAG, "Malformed URL "+e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
} catch (IOException e){
Log.e(TAG, "IOExeption "+e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
} catch (JSONException e) {
Log.d(TAG,"Json error");
Crashlytics.log(e.getLocalizedMessage());
}
}
});
thread.start();
}
}
});
void sendData(JSONObject json, final String idToken){
final String sJson = json.toString();
System.out.println(sJson);
Thread thread = new Thread(new Runnable() {
@Override
public void run() {
try {
URL url = new URL("https://indpulse.com/android");
HttpsURLConnection conn = (HttpsURLConnection) url.openConnection();
conn.setRequestMethod("POST");
conn.setRequestProperty("Authorization", "Bearer "+idToken);
conn.setDoOutput(true);
conn.setDoInput(true);
conn.connect();
DataOutputStream os = new DataOutputStream(conn.getOutputStream());
os.writeBytes(sJson);
os.flush();
os.close();
Log.i(TAG, String.valueOf(conn.getResponseCode()));
Log.i(TAG , conn.getResponseMessage());
conn.disconnect();
} catch (Exception e){
Log.e("BeaconScanner", e.getLocalizedMessage());
Crashlytics.log(e.getLocalizedMessage());
}
User.syncing = false;
}
});
thread.start();
}
编辑1
要注意的一件事是,信标具有重叠的区域,即信标扫描器将在该区域中检测到2个信标。因此,最接近的信标由
timeAverageRssi
的最大值决定,该错误专门出现了,在闲置30分钟后,出现了区域切换,即信标1最接近,然后信标2成为最接近的信标
答案 0 :(得分:0)
我怀疑在Android 8+上的Android Beacon Library 2.15版中使用前台服务存在错误。尽管我还没有自己复制过,但理论上是Android 8+阻止了Intent Service的使用,该Intent Service用于从信标扫描服务传递监视回调。
我基于类似的报告问题2.15.1 beta 1在库版本here中构建了一个建议的修复程序。请尝试此修复程序,看看是否可以解决您的问题。