web-dev-qa-db-ja.com

isValidFragment Android API 19

Android KitKatでアプリを試すと、PreferenceActivityでエラーが発生します。

PreferenceActivityのサブクラスは、フラグメントクラスが有効であることを確認するためにisValidFragment(String)をオーバーライドする必要があります! com.crbin1.labeltodo.ActivityPreferenceは、フラグメントcom.crbin1.labeltodo.StockPreferenceFragmentが有効かどうかをチェックしていません

ドキュメントには、次の説明があります

protected boolean isValidFragment(String fragmentName)

APIレベル19で追加

サブクラスはこのメソッドをオーバーライドし、指定されたフラグメントがこのアクティビティにアタッチされる有効なタイプであることを確認する必要があります。 KitKatより古いAndroid:targetSdkVersion用にビルドされたアプリの場合、デフォルトの実装はtrueを返します。それ以降のバージョンでは、例外がスローされます。

問題を解決する例が見つかりません。

49
crbin1

これを試してください...これがフラグメントの有効性を確認する方法です。

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

純粋な好奇心から、これも行うことができます:

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

;}
24
davidcesarino

ロードされたときに、ヘッダーリソースからフラグメント名のコピーを取得できることがわかりました。

_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);
    }
}
_

このように、更新したい場合、コードに埋め込まれたフラグメントのリストを更新することを覚えておく必要はありません。

getHeaders()と既存のヘッダーのリストを直接使用したいと思っていましたが、onBuildHeaders()の後にアクティビティが破棄され、isValidFragment()が呼び出される前に再作成されたようです。

これは、テストしているNexus 7が実際に2ペインの設定アクティビティを実行していないためです。したがって、静的リストメンバーも必要です。

19
lane

このAPIは、新しく発見された脆弱性のために追加されました。 http://ibm.co/1bAA8kF または http://ibm.co/IDm2Es をご覧ください

2013年12月10日「最近、Androidセキュリティチームへの新しい脆弱性を開示しました。[...]より正確に言うと、エクスポートされたアクティビティを使用してPreferenceActivityクラスを拡張したアプリは、自動的に脆弱になります。Android KitKat。コードが壊れている理由がわからない場合は、 Android KitKatパッチにより、アプリケーションは新しいメソッドPreferenceActivity.isValidFragmentをオーバーライドする必要があります。PreferenceActivity.isValidFragmentは、Android Framework。 "-From上記の最初のリンク

18
Roee Hay

実際の4.4デバイスで検証済み:

(1)proguard.cfgファイルに次の行がある場合( とにかく多くの人が定義しています ):

-keep public class com.fullpackage.MyPreferenceFragment

(2)最も効率的な実装は次のとおりです。

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

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

   }
}
3
Amir Uval

レーンの実装に議論されている脆弱性がないかどうかはわかりません here ですが、そうであれば、その静的リストの使用を避けて、次のようにするだけの方が良いと思います:

 @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

これが私の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>  

IsValidFragmentコードが発生するPreferencesActivityで、私はちょうどそれを頭につけました:

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

すべてのフラグメント名の先頭でAppPreferencesFragment文字列を使用している限り、すべて正常に検証されます。

0
James Schrumpf

ロードされたフラグメントはPreferenceFragment.classのサブクラスであると想定されるため、私のソリューションは(クラスのArrayListを作成する代わりに)@OverRideメソッドでこのチェックを実行します。

@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

これは私の解決策です:

  • 動的再構築ヘッダーが必要な場合
  • 設定アクティビティを開始するためにエクストラを使用する場合-onBuildHeaders()アプローチは失敗します! (以下の開始インテントエキストラ-なぜ???-onBuildHeaders()が呼び出されないためシンプルです):

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

これはサンプルクラスです。

/**
 * 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