如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?

Posted

技术标签:

【中文标题】如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?【英文标题】:How to send details of detected Beacon information to server in background? 【发布时间】:2018-10-04 09:32:08 【问题描述】:

我正在开发一个应用程序,该应用程序需要检测您所在地区附近的可用信标,并且检测到的信标详细信息需要使用 API 调用发送到我的服务器。 我正在获取信标详细信息,但我无法从应用程序后台将详细信息发送到我的服务器,发现任何信标。

这里是 Beacon 的详细信息;

    private class ScanProcessor extends AsyncTask<ScanData, Void, Void> 

        @Override
        protected Void doInBackground(ScanData... params) 
            ScanData scanData = params[0];

           IBeacon iBeacon = IBeacon.fromScanData(scanData.scanRecord, scanData.rssi);
           if (iBeacon != null) 
               lastIBeaconDetectionTime = new Date();
               trackedBeacons.add(iBeacon);
               Log.d(TAG, "iBeacon detected :"+iBeacon.getProximityUuid()+" Major: "+iBeacon.getMajor()+" Minor: "+iBeacon.getMinor()+" accuracy: "+iBeacon.getAccuracy()+" proximity: "+iBeacon.getProximity());

               List<Region> matchedRegions = matchingRegions(iBeacon, monitoredRegionState.keySet());
               Iterator<Region> matchedRegionIterator = matchedRegions.iterator();
               while (matchedRegionIterator.hasNext()) 
                   Region region = matchedRegionIterator.next();
                   MonitorState state = monitoredRegionState.get(region);
//                 if (state.markInside()) 
//                        state.getCallback().call(IBeaconService.this, "monitoringData", new MonitoringData(state.isInside(), region));
//                 
               

               Log.d(TAG, "looking for ranging region matches for this ibeacon");
               matchedRegions = matchingRegions(iBeacon, rangedRegionState.keySet());
               matchedRegionIterator = matchedRegions.iterator();
               while (matchedRegionIterator.hasNext()) 
                   Region region = matchedRegionIterator.next();
                   Log.d(TAG, "matches ranging region: "+region);
                   RangeState rangeState = rangedRegionState.get(region);
                   rangeState.addIBeacon(iBeacon);                 
               

           
           //I see a device: 00:02:72:C5:EC:33 with scan data: 02 01 1A 1A FF 4C 00 02 15 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E D0 00 00 69 C5 0000000000000000000000000000000000000000000000000000000000000000
           //
           // 9: proximityUuid (16 bytes) 84 2A F9 C4 08 F5 11 E3 92 82 F2 3C 91 AE C0 5E
           // 25: major (2 bytes unsigned int)
           // 27: minor (2 bytes unsigned int)
           // 29: tx power (1 byte signed int)          
            return null;
              

        @Override
        protected void onPostExecute(Void result) 
        

        @Override
        protected void onPreExecute() 
        

        @Override
        protected void onProgressUpdate(Void... values) 
        
       

当我在应用后台找到信标时,请帮助我如何将信标详细信息发送到我的服务器。

【问题讨论】:

你为什么不能这样做? 当应用处于后台时,您可以使用 android X Work Manager 启动一个可以向您的服务器发送数据的作业。 是的,我可以从应用程序的一个特定屏幕轻松发送 .. 但我需要从应用程序后台案例发送也请给我示例或任何 *** 解决了这种类型的链接 【参考方案1】:

首先,AsyncTask 需要 ui 线程才能工作,您可以使用任何其他线程 api:HandlerThread、custom handler、ExecutorService 或只是一个普通线程。您可以从here 和here 阅读更多详细信息。

另一个仅供参考,从后台检测信标我希望您没有使用正常服务,它可能会导致您在 Oreo 及以上设备上出现问题。请改用foregroundService。从here 了解服务here 及其原因。

【讨论】:

【参考方案2】:

虽然您没有显示任何尝试将数据发送到服务器的代码,但由于您已成功使用 AsyncTask 处理信标数据,您还可以使用另一个 AsyncTask 将数据发送到服务器 - 主体是相同的.

例子:

public class AsyncCaller extends AsyncTask<Void, Void, Void> 

    public RestResponseHandler mResponseHandler;
    public String mUrl;
    public String mOperation;
    public String mRequestBody;
    public Map<String,String> mRequestHeaders;
    Map<String,List<String>> mResponseHeaders;
    int mResponseCode;
    String mResponseBody;
    Exception mException;


    public AsyncCaller prepareCall(String url, String operation, String requestBody, Map<String,String> headers, RestResponseHandler responseHandler) 
        mResponseHandler = responseHandler;
        mOperation = operation;
        mRequestBody = requestBody;
        mUrl = url;
        mRequestHeaders = mRequestHeaders;
        return this;
    

    @Override
    protected void onPreExecute() 
        super.onPreExecute();
        mRequestActive = true;
    

    @Override
    protected Void doInBackground(Void... params) 
        Log.d(TAG, "start doInBackground");

        mException = null;
        try 
            sendRequest();
        
        catch (Exception e) 
            Log.e(TAG, "Cannot send request", e);
            mException = new Exception("Cannot send request", e);
        
        Log.d(TAG, "finish doInBackground");
        return null;
    

    @Override
    protected void onPostExecute(Void result) 
        Log.d(TAG, "start onPostExecute");
        super.onPostExecute(result);
        mRequestActive = false;
        if (mResponseHandler != null) 
            if (mException != null) 
                mResponseHandler.onFail(mException);
            
            else 
                mResponseHandler.onResponse(mResponseCode, mResponseHeaders, mResponseBody );
            
        
        Log.d(TAG, "finish onPostExecute");
    

    public void sendRequest() throws Exception 
        StringBuilder responseBuilder = new StringBuilder();
        HttpURLConnection conn = null;
        URL url = new URL(mUrl);
        mResponseCode = -1;
        mResponseBody = null;
        mResponseHeaders = null;
        Log.d(TAG, "calling service at " + mUrl);
        conn = (HttpURLConnection) url.openConnection();
        for (String headerKey : mRequestHeaders.keySet()) 
            conn.addRequestProperty(headerKey, mRequestHeaders.get(headerKey));
        
        conn.setRequestMethod(mOperation.toUpperCase());
        if (mRequestBody != null) 
            OutputStream out = conn.getOutputStream();
            try 
                Writer writer = new OutputStreamWriter(out, "UTF-8");
                Log.d(TAG, "posting: " + mRequestBody);
                writer.write(mRequestBody);
                writer.close();
             finally 
                if (out != null) 
                    out.close();
                
            
        
        mResponseCode = conn.getResponseCode();
        mResponseHeaders = conn.getHeaderFields();


        Log.d(TAG, "response code is " + conn.getResponseCode());
        BufferedReader in = null;
        try 
            if (mResponseCode >= 200 && mResponseCode <= 299) 
                in = new BufferedReader(
                        new InputStreamReader(
                                conn.getInputStream())
                );

            
            else 
                in = new BufferedReader(
                        new InputStreamReader(
                                conn.getErrorStream()
                        )
                );

            
            String inputLine;
            while ((inputLine = in.readLine()) != null)
                responseBuilder.append(inputLine);
            in.close();
            Log.d(TAG, "response is " + responseBuilder.toString());
            mResponseBody = responseBuilder.toString();
         finally 
            if (in != null) 
                in.close();
            
        
    


public interface RestResponseHandler 
    public void onFail(Exception e);
    public void onResponse(int httpStatus, Map<String,List<String>> headers, String body);

然后你可以调用它:

    mAsyncCsller = new AsyncCaller();
    mAsyncCaller.mUrl = "https://myserver.ner/path";
    mAsyncCaller.mOperation = "POST";
    mAsyncCaller.mRequestBody = "\uuid\":\""+beacon.getId1()+"\"";
    mAsyncCaller.mRequestHeaders = new HashMap<String,String>();
    mAsyncCaller.mResponseHandler = null;
    mAsyncCaller.execute(null, null, null);

注意不要过于频繁地向服务器发送数据。服务器调用可能需要一秒或更长时间,并且可以更频繁地检测到信标。如果您过于频繁地发送数据,您将耗尽线程并使服务器过载。考虑对您的调用进行批处理,以便每隔 60 秒将多个信标检测发送到服务器。

【讨论】:

感谢@david 的回复。但是你能帮我在后台应用程序时如何打电话吗?我需要从哪里调用我的服务器? 您是否在询问如何以编程方式确定您的应用何时处于后台? 是的,大卫我可以在应用程序处于后台时检测到信标。但是我如何使用该页面的 api 调用来调用我的服务器?即使应用程序也在后台,我是否需要在我的应用程序中运行任何后台服务或作业来发送呼叫......?如果是,那么请您提供我的样品

以上是关于如何在后台将检测到的 Beacon 信息的详细信息发送到服务器?的主要内容,如果未能解决你的问题,请参考以下文章

iPhone4S 在 Beacon 检测中的奇怪行为

Swift 2 Beacon 在后台扫描

扑动 Firebase 动画列表视图如何将数据传递到详细信息屏幕

802.11 ------ Beacon帧Beacon IntervalTBTTListen IntervalTIMDTIM

当设备已经在 Beacon 范围内时无法检测到 Beacon 然后我们打开蓝牙 & 应用程序被杀死

网卡信息检测与网络流量检测