【问题标题】:Android Google Map SDK - Working only when app launched trough adbAndroid Google Map SDK - 仅在应用程序通过 adb 启动时工作
【发布时间】:2020-07-15 10:31:28
【问题描述】:

我正在编写一个应用程序,我必须在其中显示一个 Google 地图 标准片段并在其上绘制移动设备的更新位置(此应用程序中的 GCS) .该应用似乎只有在远程设备上通过 Android Studio 启动时才能正常工作。如果我尝试直接从设备本身启动它,地图永远不会准备好:它会显示但细节非常少。

package myapp.activities;

import android.Manifest;
import android.annotation.SuppressLint;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.util.Log;
import android.view.View;

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.FragmentActivity;

import com.google.android.gms.maps.CameraUpdate;
import com.google.android.gms.maps.CameraUpdateFactory;
import com.google.android.gms.maps.GoogleMap;
import com.google.android.gms.maps.OnMapReadyCallback;
import com.google.android.gms.maps.SupportMapFragment;
import com.google.android.gms.maps.model.BitmapDescriptor;
import com.google.android.gms.maps.model.BitmapDescriptorFactory;
import com.google.android.gms.maps.model.CameraPosition;
import com.google.android.gms.maps.model.LatLng;
import com.google.android.gms.maps.model.Marker;
import com.google.android.gms.maps.model.MarkerOptions;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;
import java.util.List;

import myapp.R;

public class MapsActivity extends FragmentActivity implements OnMapReadyCallback, ActivityCompat.OnRequestPermissionsResultCallback, LocationListener {
    private static final int PERMISSION_REQUEST_LOCATION = 11;
    private static final int LOCATION_UPDATE_DELAY = 1000;

    private final String gps_provider = LocationManager.GPS_PROVIDER;

    private GoogleMap map;
    private Location location;
    private LocationManager location_manager;
    private View layout;
    private BitmapDescriptor base_icon;
    private MarkerOptions base_marker_options;
    private Marker base_marker;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_maps);

        SupportMapFragment mapFragment = (SupportMapFragment) getSupportFragmentManager()
                .findFragmentById(R.id.map);

        if (mapFragment != null)
            mapFragment.getMapAsync(this);

        //USER CODE

        layout = findViewById(R.id.map);
        assert layout != null;
   
        location = new Location(getString(R.string.location_provider));
        location.isFromMockProvider();

        base_icon = BitmapDescriptorFactory.fromResource(R.drawable.base);

        base_marker_options = new MarkerOptions().title(getString(R.string.destination_base_label)).icon(base_icon);

        initLocalization();
        //
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
        if (requestCode == PERMISSION_REQUEST_LOCATION) {
            if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                Snackbar.make(layout, R.string.fine_location_access_granted, Snackbar.LENGTH_SHORT).show();
                startLocalization();
            } else {
                Snackbar.make(layout, R.string.denied_fine_location_access_rationale, Snackbar.LENGTH_SHORT).show();
            }
        }
    }

    @Override
    public void onMapReady(GoogleMap googleMap) {
        map = googleMap;

        map.getUiSettings().setZoomControlsEnabled(true);
        map.getUiSettings().setCompassEnabled(true);
    }

    @Override
    protected void onStart() {
        super.onStart();
    }

    @Override
    protected void onStop() {
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        stopTelemetry();
    }

    @Override
    public void onLocationChanged(Location location) {
        this.location.set(location);

        if (map != null) {
            updateGCS(location);
        }
    }

    @Override
    public void onStatusChanged(String s, int i, Bundle bundle) {
    }

    @Override
    public void onProviderEnabled(String s) {
    }

    @Override
    public void onProviderDisabled(String s) {
    }
    
private void updateGCS(final Location location) {
    if(map==null)
        return;

    final LatLng latLng = new LatLng(location.getLatitude(), location.getLongitude());

    if (base_marker == null) {
        base_marker_options.position(latLng);
        base_marker = map.addMarker(base_marker_options);
    } else
        base_marker.setPosition(latLng);

    final float _zoom = map.getCameraPosition().zoom;

    final CameraPosition _cp = new CameraPosition.Builder().target(latLng).zoom(_zoom).build();
    final CameraUpdate _cu = CameraUpdateFactory.newCameraPosition(_cp);

    map.animateCamera(_cu);
}
    
    private void requestLocationPermission() {
        if (ActivityCompat.shouldShowRequestPermissionRationale(this,
                Manifest.permission.ACCESS_FINE_LOCATION)) {
            Snackbar.make(layout, R.string.denied_fine_location_access_rationale,
                    Snackbar.LENGTH_INDEFINITE).setAction(R.string.ok, new View.OnClickListener() {
                @Override
                public void onClick(View view) {
                    ActivityCompat.requestPermissions(MapsActivity.this,
                            new String[]{Manifest.permission.ACCESS_FINE_LOCATION},
                            PERMISSION_REQUEST_LOCATION);
                }
            }).show();

        } else {
            Snackbar.make(layout, R.string.denied_fine_location_access_warning, Snackbar.LENGTH_SHORT).show();
            ActivityCompat.requestPermissions(this,
                    new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, PERMISSION_REQUEST_LOCATION);
        }
    }

    private void initLocalization() {
        if (ActivityCompat.checkSelfPermission(this,
                Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
            Snackbar.make(layout,
                    R.string.fine_location_access_granted,
                    Snackbar.LENGTH_SHORT).show();
            startLocalization();
        } else {
            requestLocationPermission();
        }
    }

    @SuppressLint("MissingPermission")
    private void startLocalization() {
        try {
            location_manager = (LocationManager) getSystemService(LOCATION_SERVICE);

            if (!location_manager.isProviderEnabled(gps_provider)) {
                Intent gpsOptionsIntent = new Intent(
                        android.provider.Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                startActivity(gpsOptionsIntent);
            } else {
                location_manager.requestLocationUpdates(gps_provider, LOCATION_UPDATE_DELAY, 2, this);
            }
        } catch (Throwable e) {
            Log.e(getClass().getName(), "Exception: " + e.getMessage());
        }
    }   
}

【问题讨论】:

  • 可能与release/debug api key有关?

标签: java android google-maps


【解决方案1】:

那是释放键的问题。您已经使用调试密钥设置了配置,但您还需要发布密钥配置。有几个步骤。 您需要 Api 密钥,如果没有,请检查链接 https://developers.google.com/maps/documentation/android-sdk/get-api-key 如果您仅将其用于 Android,则限制 Android SDK 的密钥 对于调试和发布密钥检查链接https://developer.android.com/studio/publish/app-signing#debug-mode 注意:您必须提供调试、发布和 Google Play 控制台 SHA-1 指纹证书。如果您需要帮助,请查看此答案How to get the SHA-1 fingerprint certificate in Android Studio for debug mode? 配置它并享受它。

【讨论】:

  • 感谢您的回答。我已经按照 Android Studio 生成的google_maps_api.xml 文件中的链接生成了 Google API 密钥,我认为这是调试 api 密钥。下一步是从 SHA1 指纹发布证书开始创建发布 API 密钥,但我怎样才能得到这个?我有点困惑
  • @weirdgyn 抱歉,我提供的最后一个链接错误。请查看此链接stackoverflow.com/questions/15727912/… 获取释放密钥 SHA-1 指纹。
【解决方案2】:

Abubakar 回答是一个很好的开始提示,但我想对我遵循的整个过程添加评论:

  • 通过Generate Signed Bundle 或 APKBuild 菜单)创建您自己的密钥库,我这样做只是为了 release build,
  • 从头开始(在 Google 开发者控制台上)开始一个项目,
  • 在新项目上启用 Google Map Android SDK
  • 使用应用包 ID(来自 AndroidManifest.xml)和 SHA1 签名将 API 密钥限制为 Android 应用,
  • 使用生成的密钥更新清单 com.google.android.geo.API_KEY 引用。

要创建 SHA1 密钥,请使用 Java SDK 中的密钥库文件 (.jks) 和 keytool 行命令(上述 cmets 中提供的命令行)。

注意:创建密钥库后,弹出窗口会邀请您将其转换为不同的格式。只需按照提示使用对话框中提供的命令即可。

顺便说一句,debugrelease com.google.android.geo.API_KEY 引用(如果您使用标准 Android Studio 向导)应该指向相同的 api 键值,否则 Google 地图的 组件将抛出异常,抱怨身份验证失败。

【讨论】:

    猜你喜欢
    • 2012-07-10
    • 1970-01-01
    • 2015-03-01
    • 1970-01-01
    • 2015-07-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-02
    相关资源
    最近更新 更多