前台服务在didExitRegion上重新启动

问题描述 投票:1回答:1

我正在构建一个应用程序来检测Android上的iBeacons。基本功能是通过信标将广告数据存储到设备上并将其上传到服务器。为此,我正在使用Android Beacon Library。

要在Android O的后台运行它,我正在使用前台服务。问题是当应用程序在后台运行超过30分钟时,在检测到信标后,当用户退出信标区域并调用didExitRegion时,不知何故,该服务会自动终止并重新启动,因此没有数据上传到服务器。同样在重新启动后,在第二次didExitRegion调用时,它会在将来的某个时间完全停止,它会重新启动,但会重新执行相同的循环。

应用程序在非活动状态约30分钟后进入区域时发生的事件顺序

First Restart after didExit(图片仅供参考) 在这里你可以看到从11区到9区的切换。中途应用程序即时关闭并重新触发,但没有发送推送

Exit after second didExit(图片仅供参考) 接下来:当现在退出此区域时,app会再次停在后台。但这次不会立即重新触发。这是始终发生的确切顺序。

代码片段 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成为最近的信标

android android-8.0-oreo ibeacon-android android-ibeacon
1个回答
0
投票

我怀疑在Android 8+上使用Android Beacon Library版本2.15的前台服务存在错误。虽然我自己没有重现,但理论上说Android 8+阻止了用于从信标扫描服务提供监控回调的Intent服务的使用。

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

© www.soinside.com 2019 - 2024. All rights reserved.