it-swarm.com.de

isValidFragment Android API 19

Wenn ich meine App mit Android KitKat versuche, habe ich einen Fehler in PreferenceActivity.

Unterklassen von PreferenceActivity müssen isValidFragment (String) überschreiben, um sicherzustellen, dass die Fragment-Klasse gültig ist! com.crbin1.labeltodo.ActivityPreference hat nicht geprüft, ob das Fragment com.crbin1.labeltodo.StockPreferenceFragment gültig ist

In der Dokumentation finde ich folgende Erklärung

geschütztes boolean isValidFragment (String fragmentName) 

In API Level 19 hinzugefügt

Unterklassen sollten diese Methode überschreiben und sicherstellen, dass das angegebene Fragment ein gültiger Typ ist, der an diese Aktivität angehängt werden soll. Die Standardimplementierung gibt true für Apps zurück, die für Android erstellt wurden: targetSdkVersion älter als KitKat. Bei späteren Versionen wird eine Ausnahme ausgelöst.

Ich finde kein Beispiel, um das Problem zu lösen.

49
crbin1

Probieren Sie dies aus ... So prüfen wir die Gültigkeit des Fragments.

protected boolean isValidFragment(String fragmentName) {
  return StockPreferenceFragment.class.getName().equals(fragmentName);
}
65
user2098324

Aus reiner Neugier können Sie dies auch tun:

@Override
protected boolean isValidFragment(String fragmentName) {
    return MyPreferenceFragmentA.class.getName().equals(fragmentName)
            || MyPreferenceFragmentB.class.getName().equals(fragmentName)
            || // ... Finish with your last fragment.

;}
24
davidcesarino

Ich fand, dass ich eine Kopie meiner Fragmentnamen aus meiner Header-Ressource holen konnte, während sie geladen wurde:

public class MyActivity extends PreferenceActivity
{
    private static List<String> fragments = new ArrayList<String>();

    @Override
    public void onBuildHeaders(List<Header> target)
    {
        loadHeadersFromResource(R.xml.headers,target);
        fragments.clear();
        for (Header header : target) {
            fragments.add(header.fragment);
        }
    }
...
    @Override
    protected boolean isValidFragment(String fragmentName)
    {
        return fragments.contains(fragmentName);
    }
}

Auf diese Weise muss ich nicht daran denken, eine Liste der im Code vergrabenen Fragmente zu aktualisieren, wenn ich sie aktualisieren möchte.

Ich hatte gehofft, getHeaders() und die vorhandene Liste der Header direkt zu verwenden, aber es scheint, dass die Aktivität nach onBuildHeaders() zerstört und neu erstellt wird, bevor isValidFragment() aufgerufen wird.

Dies kann daran liegen, dass der Nexus 7, an dem ich gerade teste, keine Voreinstellungen für zwei Bereiche ausführt. Daher auch das statische Listenmitglied.

20
lane

Diese API wurde aufgrund einer neu entdeckten Sicherheitsanfälligkeit hinzugefügt. Siehe http://ibm.co/1bAA8kF oder http://ibm.co/IDm2Es

10. Dezember 2013 "Wir haben kürzlich eine neue Sicherheitslücke für das Android Security Team aufgedeckt. [...] Um genauer zu sein, war jede App, die die PreferenceActivity-Klasse um eine exportierte Aktivität erweitert hat, automatisch anfällig. In Android KitKat wurde ein Patch bereitgestellt fragte sich, warum der Code jetzt kaputt ist. Dies liegt an dem Patch Kit für Android KitKat, bei dem Anwendungen die neue Methode PreferenceActivity.isValidFragment außer Kraft setzen müssen, die dem Android Framework hinzugefügt wurde. " - Vom ersten Link oben

18
Roee Hay

Verifiziert mit einem aktuellen 4.4-Gerät:

(1) Wenn Ihre proguard.cfg -Datei diese Zeile hat ( die viele trotzdem definieren ):

-keep public class com.fullpackage.MyPreferenceFragment

(2) als die effizienteste Implementierung wäre:

@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public class EditPreferencesHC extends PreferenceActivity {
...
   protected boolean isValidFragment (String fragmentName) {

     return "com.fullpackage.MyPreferenceFragment".equals(fragmentName);

   }
}
3
Amir Uval

Ich bin nicht sicher, ob die Implementierung von Lane frei von den besprochenen Schwachstellen ist here , aber wenn dies der Fall ist, denke ich, wäre es eine bessere Lösung, diese statische Liste zu vermeiden und einfach Folgendes zu tun:

 @Override
    protected boolean isValidFragment(String fragmentName)
    {
        ArrayList<Header> target = new ArrayList<>();
        loadHeadersFromResource(R.xml.pref_headers, target);
        for (Header h : target) {
            if (fragmentName.equals(h.fragment)) return true;
        }
        return false;
    }
3
Ofek Ron

Hier ist meine Datei headers_preferences.xml: 

<?xml version="1.0" encoding="utf-8"?>  
<preference-headers  
xmlns:Android="http://schemas.Android.com/apk/res/Android">  

    <header  

        Android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs1Fragment"  
        Android:title="Change Your Name" />  

    <header  
        Android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs2Fragment"  
        Android:title="Change Your Group''s Name" />  

    <header  
        Android:fragment="com.gammazero.signalrocket.AppPreferencesFragment$Prefs3Fragment"  
        Android:title="Change Map View" />  

</preference-headers>  

In meiner PreferencesActivity, wo der Code isValidFragment vorkommt, habe ich ihn einfach auf den Kopf gestellt:

@Override
protected boolean isValidFragment(String fragmentName)
{
  //  return AppPreferencesFragment.class.getName().contains(fragmentName);
    return fragmentName.contains (AppPreferencesFragment.class.getName());
}

Solange ich die AppPreferencesFragment-Zeichenfolge am Anfang aller meiner Fragmentnamen verwende, werden sie alle einwandfrei überprüft.

0
James Schrumpf

meine Lösung (anstatt ArrayList der Klasse zu erstellen), da die geladenen Fragmente eine Unterklasse von PreferenceFragment.class annehmen, führen Sie diese Prüfung in der @ OverRide-Methode aus

@Override
protected boolean isValidFragment(String fragmentName) {
    try {
        Class cls = Class.forName(fragmentName);
        return (cls.getSuperclass().equals(PreferenceFragment.class));
                                  // true if superclass is PreferenceFragmnet
    } catch (ClassNotFoundException e) {
        e.printStackTrace();
    }
    return false;
}
0
ItzikH

das ist meine Lösung:

  • wenn Sie dynamische Header für die Neuerstellung benötigen 
  • wenn Sie Extras verwenden, um die Präferenzaktivität zu starten, schlägt der Ansatz von onBuildHeaders () fehl! (mit unten genannten Vorsatz-Extras - warum ??? - einfach, weil onBuildHeaders () nie aufgerufen wird):

    Intent.putExtra (PreferenceActivity.EXTRA_SHOW_FRAGMEN, Fragment.class.getName ()); Intent.putExtra (PreferenceActivity.EXTRA_NO_HEADERS, true);

Dies ist eine Beispielklasse:

/**
 * Preference Header for showing settings and add view as two panels for tablets
 * for ActionBar we need override onCreate and setContentView
 */
public class SettingsPreferenceActivity extends PreferenceActivity {

    /** valid fragment list declaration */
    private List<String> validFragmentList;

    /** some example irrelevant class for holding user session  */
    SessionManager _sessionManager;

    @Override
    public void onBuildHeaders(List<Header> target) {
        /** load header from res */
        loadHeadersFromResource(getValidResId(), target);
    }

    /**
     * this API method was added due to a newly discovered vulnerability.
     */
    @Override
    protected boolean isValidFragment(String fragmentName) {
        List<Header> headers = new ArrayList<>();
        /** fill fragments list */
        tryObtainValidFragmentList(getValidResId(), headers);
        /** check  id valid */
        return validFragmentList.contains(fragmentName);
    }

    /** try fill list of valid fragments */
    private void tryObtainValidFragmentList(int resourceId, List<Header> target) {  
        /** check for null */
        if(validFragmentList==null) {
            /** init */
            validFragmentList = new ArrayList();
        } else {
            /** clear */
            validFragmentList.clear();
        }
        /** load headers to list */
        loadHeadersFromResource(resourceId, target);
        /** set headers class names to list */
        for (Header header : target) {
            /** fill */
            validFragmentList.add(header.fragment);
        }
    }

    /** obtain valid res id to build headers */
    private int getValidResId() {
        /** get session manager */
        _sessionManager = SessionManager.getInstance();
        /** check if user is authorized */
        if (_sessionManager.getCurrentUser().getWebPart().isAuthorized()) {
            /** if is return full preferences header */
            return R.xml.settings_preferences_header_logged_in;
        } else {
            /** else return short header */
            return R.xml.settings_preferences_header_logged_out;
        }
    }
}
0
ceph3us