Android FusedLocationProviderApi:传入意图没有LocationResult或LocationAvailability

Posted

技术标签:

【中文标题】Android FusedLocationProviderApi:传入意图没有LocationResult或LocationAvailability【英文标题】:Android FusedLocationProviderApi: Incoming intent has no LocationResult or LocationAvailability 【发布时间】:2015-12-29 19:52:18 【问题描述】:

我正在尝试通过 Google 的 FusedLocationProviderApi 订阅位置更新。我想在后台接收更新,这样即使应用程序被杀死我也会收到更新。尽我所能遵循在线文档,我编写了以下代码。注意:这是在意图服务中完成的,而不是在 UI 线程中完成的,这就是我使用阻塞连接/结果方法的原因。

private void startLocationServices(String deviceId, int pollingInterval) 
    Log.i(TAG, "Starting location services with interval: " + pollingInterval + "ms");
    PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
    final PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
    wakeLock.acquire();

    final GoogleApiClient googleApiClient =
            new GoogleApiClient.Builder(this)
                    .addApi(LocationServices.API)
                    .build();

    ConnectionResult result = googleApiClient.blockingConnect();

    if (!result.isSuccess() || !googleApiClient.isConnected()) 
        Log.e(TAG, "Failed to connect to Google Api");
        wakeLock.release();
        return;
    

    LocationRequest locationRequest = new LocationRequest();
    locationRequest.setInterval(pollingInterval);
    locationRequest.setFastestInterval(10000);
    locationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY);

    Intent locationIntent = new Intent(this, GeoBroadcastReceiver.class);
    locationIntent.putExtra(EXTRA_LOCATION_UPDATE_DEVICE_ID, deviceId);
    locationIntent.setAction(GeoBroadcastReceiver.ACTION_LOCATION_UPDATE);
    PendingIntent locationPendingIntent = PendingIntent.getBroadcast(
            this, 0, locationIntent, PendingIntent.FLAG_UPDATE_CURRENT);

    PendingResult pendingResult = LocationServices.FusedLocationApi
            .requestLocationUpdates(googleApiClient, locationRequest, locationPendingIntent);

    Result requestResult = pendingResult.await();
    Status requestStatus = requestResult.getStatus();

    if (requestStatus.isSuccess()) 
        Log.i(TAG, "Successfully subscribed to location updates.");
     else 
        Log.e(TAG, String.format(
                        "Failed subscribe to location updates. Error code: %d, Message: %s.",
                        requestStatus.getStatusCode(),
                        requestStatus.getStatusMessage()));
    

    googleApiClient.disconnect();
    wakeLock.release();

当我运行它时,我看到 requestStatus.isSuccess() 返回 true,表示我已成功订阅位置更新。此外,扩展WakefulBroadcastReceiverGeoBroadcastReciever 以正确的轮询间隔接收意图,并采取正确的操作。到目前为止,看起来不错。这是我在onReceive 方法中为GeoBroadcastReceiver 所做的事情:

    if (LocationResult.hasResult(intent)) 
        LocationResult locationResult = LocationResult.extractResult(intent);
        Location location = locationResult.getLastLocation();
        if (location != null) 
            GeoMonitoringService.wakefulLocationUpdate(context, location);
         else 
            Log.e(TAG, "LocationResult does not contain a LastLocation.");
        
     else 
        Log.e(TAG, "Intent does not contain a LocationResult.");
    

问题是,每当intent进来时,它既不包含LocationResult,也不包含LocationAvailabilityResult。我在调试器中检查了传入的 Intent,Intent 的附加项中唯一的项目是我在设置 Intent 时添加的附加项(设备 ID)。因此,LocationResult.hasResult() 返回 false。每一次。

我已经在运行 4.0.1 的 Galaxy Note 4 和运行 5.1.1 的 Nexus 4 上进行了尝试,结果相同。

如果我在手机上禁用位置信息,我将完全停止接收意图,正如预期的那样。

【问题讨论】:

好的,我有更多关于这方面的数据。当我注释掉将 String Extra 添加到 Intent 之前的行,然后将其传递给 getBroadcast() 时,问题 大部分 已解决。在这种情况下,该问题仅发生在大约 20 个位置更新中的 1 个。随着 Extra 的出现,问题每次都会发生。我知道这似乎有点脆弱,但这种模式在我的两部手机上都非常可重复。添加额外的东西似乎把事情搞砸了(尽管在 ActivityRecognition 的情况下,我使用完全相同的模式,额外的存在似乎根本不重要)。 我也有同样的问题。一年前code.google.com/p/android/issues/detail?id=81812 似乎也有同样的报道。你找到解决办法了吗? 很遗憾,我还没有找到解决办法。 好的。一种解决方法(Christophe Beyls 建议应该只使用 Intent Data)所以,因为我只需要发送一些参数,所以我做这样的事情:在 requestLocationUpdates 之前构建 Intent:intent.setData(Uri.parse(" a.com/a?"+ Param1+ "?" + Param2+ "?" + Param3); 并在 BroadcastReceiver: String[] parameters = intent.getDataString().split("[?]"); 这工作正常,并且 intent.getParcelableExtra( FusedLocationProviderApi.KEY_LOCATION_CHANGED) 确实返回了位置。 找到解决方案了吗 【参考方案1】:

从待处理的 Intent 中删除 extras,否则不会传递位置结果。我在文档中找不到解释的地方,但经过大量试验和错误后我发现了。

【讨论】:

我为此提交了bug report。 我希望他们尽快查看您的错误报告。在数据 URI 中传递参数感觉很恶心。【参考方案2】:

一种解决方法(Christophe Beyls 建议应该只使用意图数据) 所以,因为我只需要发送几个参数,所以我做这样的事情: 在 requestLocationUpdates 之前构建 Intent 时: intent.setData(Uri.parse("http://a.com/a?"+ Param1+ "?" + Param2+ "?" + Param3); 在广播接收器中: String[] 参数 = intent.getDataString().split("[?]"); 这很好用,并且 intent.getParcelableExtra(FusedLocationProviderApi.KEY_LOCATION_CHANGED) 确实返回了位置。

【讨论】:

【参考方案3】:

你可以使用:

int id = 7;
String name = "myName";
uriBuilder.scheme("http")
            .authority("workaround.com")
            .appendPath("extra")
            .appendQueryParameter("id", String.valueOf(id))
            .appendQueryParameter("name", name);
intent.setData(uriBuilder.build());

@Override
protected void onHandleIntent(Intent intent) 
    if (LocationResult.hasResult(intent)) 
        int id = Integer.valueOf(uri.getQueryParameter("id"));
        String name = uri.getQueryParameter("name");
        ....
    

【讨论】:

以上是关于Android FusedLocationProviderApi:传入意图没有LocationResult或LocationAvailability的主要内容,如果未能解决你的问题,请参考以下文章

Android 逆向Android 权限 ( Android 逆向中使用的 android.permission 权限 | Android 系统中的 Linux 用户权限 )

android 21 是啥版本

Android逆向-Android基础逆向(2-2)

【Android笔记】android Toast

图解Android - Android核心机制

Android游戏开发大全的目录