前台服务在didExitRegion上重新启动

时间:2018-08-11 07:38:45

标签: android android-8.0-oreo ibeacon-android android-ibeacon

我正在构建一个应用程序来检测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成为最接近的信标

1 个答案:

答案 0 :(得分:0)

我怀疑在Android 8+上的Android Beacon Library 2.15版中使用前台服务存在错误。尽管我还没有自己复制过,但理论上是Android 8+阻止了Intent Service的使用,该Intent Service用于从信标扫描服务传递监视回调。

我基于类似的报告问题2.15.1 beta 1在库版本here中构建了一个建议的修复程序。请尝试此修复程序,看看是否可以解决您的问题。