when android's isValidFragment() from PreferenceActivity gets called?

时光总嘲笑我的痴心妄想 提交于 2019-12-04 23:08:21

问题


For some application on which I was working, for devices with API level 19 I'm getting exception

Caused by: java.lang.RuntimeException: Subclasses of PreferenceActivity must override isValidFragment(String) to verify that the Fragment class is valid! com... has not checked if fragment com...$. is valid.

Then, I found out that for those applications android frameworks protected boolean isValidFragment(String fragmentName) is getting called, which has code

if (getApplicationInfo().targetSdkVersion  >= android.os.Build.VERSION_CODES.KITKAT) {
        throw new RuntimeException(
                "Subclasses of PreferenceActivity must override isValidFragment(String)"
                + " to verify that the Fragment class is valid! " + this.getClass().getName()
                + " has not checked if fragment " + fragmentName + " is valid.");
    } else {
        return true;
}

Then I tried to replicate the error

I took my sample app's code from Preferences Activity Example and added line <uses-sdk android:targetSdkVersion="19" /> in manifest.

But strangely, I'm not getting the error(isValidFragment() not getting called in that case).

So please tell me how to replicate that error in my sample app.


回答1:


Seems to be a bug or a 4.4 security restriction. Workaraound is to use anything below 19 that is still compatible with PreferenceActivity, and bite the bullet for compiling with an older target.

I am using the headers "pattern" for the PreferenceActivity (overriding public void onBuildHeaders(List<Header> target)), and I assume the OP is too, most likely being the place where stuff happens and crashes.

In my case, I have narrowed this exception to <uses-sdk android:targetSdkVersion="19" />, and anything in [14-18] build targets will compile and run without issues.

Suggestion (for Eclipse): I never messed directly messed with such stuff, but I'm assuming if you compile your PreferenceActivity (and maybe fragments) on a different project, targeting 18 or under (pun not intended :O ), and then using that project as a library for your main project targeting KitKat (19), perhaps you can avoid the crash scenario at run-time while still using the features you need from the latest build (as long as those features aren't in the build-18-bound PreferenceActivity). If this does not succeed, try with that project in jar form (pre-compiled) instead of using project as library.

UPDATE: also take note of Camille Sévigny's answer. If the issue has anything to do with that other question (50% chance IMHO), all apps targeting API 18 are vulnerable to fragment injection attacks (see his linked question).




回答2:


The answer to your question is in this post. This is a duplicate question:

isValidFragment Android API 19

--Updated--

Here is what the solution is:

Basically, whichever Activity is using your fragment "com...$" in the error above, you must update it with the fix below. You should update all the Activities in your project with this fix for any Acitvity that uses a Fragment.

The documentation states:

protected boolean isValidFragment (String fragmentName)

Added in API level 19

Subclasses should override this method and verify that the given fragment is a 
valid type to be attached to this activity. The default implementation returns 
true for apps built for android:targetSdkVersion older than KITKAT. For later 
versions, it will throw an exception.

You can fix this error by overriding this method to the Activity/FragmentActivity:

@Override
protected boolean isValidFragment (String fragmentName) {
  return [YOUR_FRAGMENT_NAME_HERE].class.getName().equals(fragmentName);
}

If you are being lazy and just want to test out if this fix works before coding all your fragments into this method, you can simply return true without any checking:

@Override
protected boolean isValidFragment (String fragmentName) {
  return true;
}

I had the same issues when testing on the emulator and this was the solution.




回答3:


Here you go!

Slap this in there, and you're good!

Collect all the inner classes found in this PreferenceActivity. I chose to put the list in a static field variable:

public class whatever extends PreferenceActivity {

    static final Class<?>[] INNER_CLASSES = 
                                     whatever.class.getDeclaredClasses();

Then, override the method, ValidFragment, and ensure the fragment about to be displayed is one the 'parent' activity is aware of:

 /**
 *  Google found a 'security vulnerability' and imposed this hack.
 *  Have to check this fragment was actually conceived by this activity.
 */
@Override
protected boolean isValidFragment(String fragmentName) {

    Boolean knownFrag = false;

    for (Class<?> cls : INNER_CLASSES) {

       if ( cls.getName().equals(fragmentName) ){

           knownFrag = true;

           break;
       }
    }           

    return knownFrag;
}


来源:https://stackoverflow.com/questions/20954072/when-androids-isvalidfragment-from-preferenceactivity-gets-called

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!