Why my map app crashes if I set maxSdkVersion in t

2019-03-16 19:37发布

问题:

I've set my map following the instructions in this link. And set the WRITE_EXTERNAL_STORAGE permission in accordance with the recomended by the Official Android Documentation, that is request this permission only for API level 18 and lower. So, I have this manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.myapp" >

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"
                     android:maxSdkVersion="18"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.android.permission.ACCESS_COARSE_LOCATION"/>
    <uses-permission android:name="android.permission.android.permission.ACCESS_FINE_LOCATION"/>
    <uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES"/>

    <uses-feature
        android:glEsVersion="0x00020000"
        android:required="true"/>

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <uses-library android:name="com.google.android.maps"/>
        <activity
            android:name=".activities.HomeActivity" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />    
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <meta-data
            android:name="com.google.android.gms.version"
            android:value="@integer/google_play_services_version" />
        <meta-data
            android:name="com.google.android.maps.v2.API_KEY"
            android:value="@string/map_api_key"/>
    </application>

</manifest>

But I am facing this error:

Caused by: java.lang.SecurityException: The Maps API requires the additional following
permissions to be set in the AndroidManifest.xml to ensure a correct behavior: 
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

But, as it is showed in my manifest, I have this permission. One detail is if I put only the WRITE_EXTERNAL_STORAGE permission, without specifying the maxSdkVersion value, the app works properly.

Is this an Android bug or am I forgetting something in my app configuration?

UPDATE 1

This is the logcat:

 FATAL EXCEPTION: main
 Process: com.example.map, PID: 15534
 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.map/com.example.map.MainActivity}: android.view.InflateException: Binary XML file line #11: Error inflating class fragment
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2195)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2245)
    at android.app.ActivityThread.access$800(ActivityThread.java:135)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1196)
    at android.os.Handler.dispatchMessage(Handler.java:102)
    at android.os.Looper.loop(Looper.java:136)
    at android.app.ActivityThread.main(ActivityThread.java:5017)
    at java.lang.reflect.Method.invokeNative(Native Method)
    at java.lang.reflect.Method.invoke(Method.java:515)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:779)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:595)
    at dalvik.system.NativeStart.main(Native Method)
 Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class fragment
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:713)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:755)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:492)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:397)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:353)
    at com.android.internal.policy.impl.PhoneWindow.setContentView(PhoneWindow.java:290)
    at android.app.Activity.setContentView(Activity.java:1929)
    at android.support.v7.app.ActionBarActivity.superSetContentView(ActionBarActivity.java:216)
    at android.support.v7.app.ActionBarActivityDelegateICS.setContentView(ActionBarActivityDelegateICS.java:110)
    at android.support.v7.app.ActionBarActivity.setContentView(ActionBarActivity.java:76)
    at com.example.map.MainActivity.onCreate(MainActivity.java:16)
    at android.app.Activity.performCreate(Activity.java:5231)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2159)
    ... 11 more
 Caused by: java.lang.SecurityException: The Maps API requires the additional following permissions to be set in the AndroidManifest.xml to ensure a correct behavior:
 <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
    at maps.e.ci.a(Unknown Source)
    at maps.e.ay.a(Unknown Source)
    at maps.e.ay.a(Unknown Source)
    at maps.e.al.a(Unknown Source)
    at maps.e.bh.a(Unknown Source)
    at maps.e.bg.a(Unknown Source)
    at etu.onTransact(SourceFile:107)
    at android.os.Binder.transact(Binder.java:361)
    at com.google.android.gms.maps.internal.IMapFragmentDelegate$a$a.onCreateView(Unknown Source)
    at com.google.android.gms.maps.SupportMapFragment$a.onCreateView(Unknown Source)
    at com.google.android.gms.dynamic.a$4.b(Unknown Source)
    at com.google.android.gms.dynamic.a.a(Unknown Source)
    at com.google.android.gms.dynamic.a.onCreateView(Unknown Source)
    at com.google.android.gms.maps.SupportMapFragment.onCreateView(Unknown Source)
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1500)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:911)
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1093)
    at android.support.v4.app.FragmentManagerImpl.addFragment(FragmentManager.java:1195)
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:291)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:685)

UPDATE 2

My layout:

<fragment
    android:id="@+id/map"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    class="com.google.android.gms.maps.SupportMapFragment" />

UPDATE 3

public class MainActivity extends ActionBarActivity {

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

回答1:

If you check the link you've provided to the <uses-permission> documentation, you'll see that it states that:

it's no longer necessary for your app to request the WRITE_EXTERNAL_STORAGE permission when your app wants to write to its own application-specific directories on external storage (the directories provided by getExternalFilesDir()).

It would appear that the Maps API needs write access to other directories. And if you check the Specify permissions section of the other link you gave, it still lists the WRITE_EXTERNAL_STORAGE permission as required, with no mention of exception for API Level 19.


After having checked many, many online resources with regard to the Maps API, Android API Level 19, and the restriction of the WRITE_EXTERNAL_STORAGE permission, I found no source or example that listed or referenced a working example using the Maps API with that permission restricted to API Level 18 and below. Again, I quote the link you've provided that says the permission is not needed in API Level 19 "when your app wants to write to its own application-specific directories on external storage". (I would point out that it merely says it is not necessary in that case, and in no way "recommends" that you set this restriction absolutely.) The Maps API needs write-permission to external storage directories that are not owned by your app. The fact that "without specifying the maxSdkVersion value, the app works properly" indicates that even in KitKat, Maps needs that permission. The error is telling you exactly that.



回答2:

I did some research around the maxSdkVersion. And I found the following

From google http://developer.android.com/guide/topics/manifest/uses-sdk-element.html

Warning: Declaring this attribute is not recommended. First, there is no need to set the attribute as means of blocking deployment of your application onto new versions of the Android platform as they are released. By design, new versions of the platform are fully backward-compatible. Your application should work properly on new versions, provided it uses only standard APIs and follows development best practices. Second, note that in some cases, declaring the attribute can result in your application being removed from users' devices after a system update to a higher API Level. Most devices on which your application is likely to be installed will receive periodic system updates over the air, so you should consider their effect on your application before setting this attribute.

I have something like this in my current working google app

 <uses-sdk
    android:minSdkVersion="11"
    android:targetSdkVersion="17" />

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.providers.gsf.permission.READ_GSERVICES" />

<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

<uses-feature
    android:glEsVersion="0x00020000"
    android:required="true" />

So if you really want, you can try put that maxSdkVersion in the note, unless its what google is documented in the above link.

Hope this help



回答3:

The XML code provided in the link is for Android API 12 or later. Since your minSDKVersion is 8. Use this:

<fragment
        android:id="@+id/map"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        class="com.google.android.gms.maps.SupportMapFragment" />

Check here for more.