isValidFragment Android API 19
当我尝试与Android KitKat我的应用程序时,PreferenceActivity中有一个错误。
PreferenceActivity的子类必须重写isValidFragment(String)来validationFragment类是有效的! com.crbin1.labeltodo.ActivityPreference没有检查,如果片段com.crbin1.labeltodo.StockPreferenceFragment是有效的
在文档中我find了下面的解释
protected boolean isValidFragment(String fragmentName)
在API级别19中添加
子类应该重写此方法,并validation给定片段是否附加到此活动的有效types。 对于为android:targetSdkVersion构build的应用程序,默认实现将返回true,此值比KITKAT更早。 对于以后的版本,它会抛出一个exception。
我没有find任何解决问题的例子。
试试这个…这是我们如何检查片段的有效性。
protected boolean isValidFragment(String fragmentName) { return StockPreferenceFragment.class.getName().equals(fragmentName); }
出于纯粹的好奇心,你也可以这样做:
@Override protected boolean isValidFragment(String fragmentName) { return MyPreferenceFragmentA.class.getName().equals(fragmentName) || MyPreferenceFragmentB.class.getName().equals(fragmentName) || // ... Finish with your last fragment. ;}
我发现我可以从头文件资源抓取我的片段名称的副本,因为它是加载的:
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()
之前重新创build。
这可能是因为我正在testing的Nexus 7实际上并没有执行双窗格偏好活动。 因此也需要静态列表成员。
由于新发现的漏洞,已添加此API。 请参阅http://ibm.co/1bAA8kF或http://ibm.co/IDm2Es
2013年12月10日 “我们最近披露了Android安全团队的一个新漏洞[…]为了更加准确,任何使用导出的活动扩展PreferenceActivity类的应用程序都会自动受到攻击。 KitKat。如果你想知道为什么你的代码现在被破坏,这是由于Android KitKat补丁,它需要应用程序覆盖已添加到Android框架的新方法,PreferenceActivity.isValidFragment。 – 从上面的第一个链接
使用实际的4.4设备进行validation:
(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); } }
我不确定是否lane的实现没有这里讨论的漏洞,但是如果是这样,那么我认为一个更好的解决scheme是避免使用这个静态列表,并简单地执行以下操作:
@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; }
这是我的解决scheme:
- 如果你需要dynamic重build标题
-
如果你使用额外开始偏好活动 – 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; } } }
这是我的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()); }
只要我在我的所有片段名称的开始使用AppPreferencesFragmentstring,他们都validation就好了。