use of android.content.res.AssetManager in project blog_resource by Guolei1130.
the class PatchResource method pathResource.
static void pathResource(Context context, String filePath, Collection<Activity> activities) {
try {
AssetManager newAssetManager = AssetManager.class.getConstructor().newInstance();
Method mAddAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
mAddAssetPath.setAccessible(true);
if (((Integer) mAddAssetPath.invoke(newAssetManager, filePath)) == 0) {
throw new IllegalStateException("Could not create new AssetManager");
}
Method mEnsureStringBlocks = AssetManager.class.getDeclaredMethod("ensureStringBlocks");
mEnsureStringBlocks.setAccessible(true);
mEnsureStringBlocks.invoke(newAssetManager);
if (activities != null) {
for (Activity activity : activities) {
Resources resources = activity.getResources();
try {
// 7.0之前,用的mAssets
Field mAssets = Resources.class.getDeclaredField("mAssets");
mAssets.setAccessible(true);
mAssets.set(resources, newAssetManager);
} catch (Exception e) {
// 7.0及以后版本,用的mResourcesImpl#mAssets
Field mResourcesImpl = Resources.class.getDeclaredField("mResourcesImpl");
mResourcesImpl.setAccessible(true);
Object resourceImpl = mResourcesImpl.get(resources);
Field implAssets = resourceImpl.getClass().getDeclaredField("mAssets");
implAssets.setAccessible(true);
implAssets.set(resourceImpl, newAssetManager);
}
// 使用者可能哟通过getTheme.getResource 去获取资源,因此,需要替换掉theme中的
Resources.Theme theme = activity.getTheme();
try {
// 版本差异
try {
Field ma = Resources.Theme.class.getDeclaredField("mAssets");
ma.setAccessible(true);
ma.set(theme, newAssetManager);
} catch (Exception e) {
Field themeField = Resources.Theme.class.getDeclaredField("mThemeImpl");
themeField.setAccessible(true);
Object impl = themeField.get(theme);
Field ma = impl.getClass().getDeclaredField("mAssets");
ma.setAccessible(true);
ma.set(impl, newAssetManager);
}
// 重新初始化Theme
Field mt = ContextThemeWrapper.class.getDeclaredField("mTheme");
mt.setAccessible(true);
mt.set(activity, null);
Method mtm = ContextThemeWrapper.class.getDeclaredMethod("initializeTheme");
mtm.setAccessible(true);
mtm.invoke(activity);
Method mCreateTheme = AssetManager.class.getDeclaredMethod("createTheme");
mCreateTheme.setAccessible(true);
Object internalTheme = mCreateTheme.invoke(newAssetManager);
Field mTheme = Resources.Theme.class.getDeclaredField("mTheme");
mTheme.setAccessible(true);
mTheme.set(theme, internalTheme);
} catch (Exception e) {
e.printStackTrace();
}
pruneResourceCaches(resources);
}
}
// 替换掉缓存起来的
Collection<WeakReference<Resources>> references;
if (SDK_INT >= KITKAT) {
Class<?> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
Method mGetInstance = resourcesManagerClass.getDeclaredMethod("getInstance");
mGetInstance.setAccessible(true);
Object resourcesManager = mGetInstance.invoke(null);
try {
Field fMActiveResources = resourcesManagerClass.getDeclaredField("mActiveResources");
fMActiveResources.setAccessible(true);
@SuppressWarnings("unchecked") ArrayMap<?, WeakReference<Resources>> arrayMap = (ArrayMap<?, WeakReference<Resources>>) fMActiveResources.get(resourcesManager);
references = arrayMap.values();
} catch (NoSuchFieldException ignore) {
Field mResourceReferences = resourcesManagerClass.getDeclaredField("mResourceReferences");
mResourceReferences.setAccessible(true);
// noinspection unchecked
references = (Collection<WeakReference<Resources>>) mResourceReferences.get(resourcesManager);
}
} else {
Class<?> activityThread = Class.forName("android.app.ActivityThread");
Field fMActiveResources = activityThread.getDeclaredField("mActiveResources");
fMActiveResources.setAccessible(true);
Object thread = getActivityThread(context, activityThread);
@SuppressWarnings("unchecked") HashMap<?, WeakReference<Resources>> map = (HashMap<?, WeakReference<Resources>>) fMActiveResources.get(thread);
references = map.values();
}
for (WeakReference<Resources> wr : references) {
Resources resources = wr.get();
if (resources != null) {
// Set the AssetManager of the Resources instance to our brand new one
try {
Field mAssets = Resources.class.getDeclaredField("mAssets");
mAssets.setAccessible(true);
mAssets.set(resources, newAssetManager);
} catch (Throwable ignore) {
Field mResourcesImpl = Resources.class.getDeclaredField("mResourcesImpl");
mResourcesImpl.setAccessible(true);
Object resourceImpl = mResourcesImpl.get(resources);
Field implAssets = resourceImpl.getClass().getDeclaredField("mAssets");
implAssets.setAccessible(true);
implAssets.set(resourceImpl, newAssetManager);
}
resources.updateConfiguration(resources.getConfiguration(), resources.getDisplayMetrics());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
use of android.content.res.AssetManager in project XUtil by xuexiangjys.
the class ResourceUtils method getImageFromAssetsFile.
/**
* 从Assets中读取图片
*/
public static Bitmap getImageFromAssetsFile(String fileName) {
Bitmap image = null;
AssetManager am = getAssetManager();
try {
InputStream is = am.open(fileName);
image = BitmapFactory.decodeStream(is);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
return image;
}
use of android.content.res.AssetManager in project AndroidLife by CaMnter.
the class MonkeyPatcher method monkeyPatchExistingResources.
/**
* 1. 反射调用 AssetManager.addAssetPath 方法加载 补丁资源
* 2. Hook Resource or ResourcesImpl 中的 mAssets,Hook 为 补丁资源
* 3. Hook Resource or ResourcesImpl 内 Theme or ThemeImpl 中的 mAssets,Hook 为 补丁资源
* 4. Hook Activity( ContextThemeWrapper )的 initializeTheme 方法去初始化 Theme
* 5. 如果 < 7.0, 先 Hook AssetManager 的 createTheme 方法去创建一个 补丁 Theme
* 然后 Hook Activity 的 Theme 的 mTheme Field 为 补丁 Theme
* 6. 调用 pruneResourceCaches(@NonNull Object resources) 方法去删除 资源缓存
*
* @param context context
* @param externalResourceFile 外部资源 path
* @param activities 运行 activity
*/
public static void monkeyPatchExistingResources(@Nullable Context context, @Nullable String externalResourceFile, @Nullable Collection<Activity> activities) {
if (externalResourceFile == null) {
return;
}
try {
/**
* Step 1
*
* 反射 AssetManager#addAssetPath 方法
* 加载补丁资源的 AssetManager
*/
// Create a new AssetManager instance and point it to the resources installed under
// /sdcard
AssetManager newAssetManager = AssetManager.class.getConstructor().newInstance();
Method mAddAssetPath = AssetManager.class.getDeclaredMethod("addAssetPath", String.class);
mAddAssetPath.setAccessible(true);
if (((Integer) mAddAssetPath.invoke(newAssetManager, externalResourceFile)) == 0) {
throw new IllegalStateException("Could not create new AssetManager");
}
/**
* Step 2
*
* 反射 Hook 补丁资源 AssetManager 的 ensureStringBlocks Field 为 true
* 下面注释告诉,4.4 需要这么做
*/
// Kitkat needs this method call, Lollipop doesn't. However, it doesn't seem to cause any harm
// in L, so we do it unconditionally.
Method mEnsureStringBlocks = AssetManager.class.getDeclaredMethod("ensureStringBlocks");
mEnsureStringBlocks.setAccessible(true);
mEnsureStringBlocks.invoke(newAssetManager);
if (activities != null) {
for (Activity activity : activities) {
Resources resources = activity.getResources();
try {
Field mAssets = Resources.class.getDeclaredField("mAssets");
mAssets.setAccessible(true);
mAssets.set(resources, newAssetManager);
} catch (Throwable ignore) {
Field mResourcesImpl = Resources.class.getDeclaredField("mResourcesImpl");
mResourcesImpl.setAccessible(true);
Object resourceImpl = mResourcesImpl.get(resources);
Field implAssets = resourceImpl.getClass().getDeclaredField("mAssets");
implAssets.setAccessible(true);
implAssets.set(resourceImpl, newAssetManager);
}
Resources.Theme theme = activity.getTheme();
try {
try {
Field ma = Resources.Theme.class.getDeclaredField("mAssets");
ma.setAccessible(true);
ma.set(theme, newAssetManager);
} catch (NoSuchFieldException ignore) {
Field themeField = Resources.Theme.class.getDeclaredField("mThemeImpl");
themeField.setAccessible(true);
Object impl = themeField.get(theme);
Field ma = impl.getClass().getDeclaredField("mAssets");
ma.setAccessible(true);
ma.set(impl, newAssetManager);
}
/**
* Step 5
*
* Hook Activity( ContextThemeWrapper )的 mTheme Field 为 null
* Hook Activity( ContextThemeWrapper )的 initializeTheme 方法去初始化 Theme
*/
Field mt = ContextThemeWrapper.class.getDeclaredField("mTheme");
mt.setAccessible(true);
mt.set(activity, null);
Method mtm = ContextThemeWrapper.class.getDeclaredMethod("initializeTheme");
mtm.setAccessible(true);
mtm.invoke(activity);
if (SDK_INT < 24) {
// As of API 24, mTheme is gone (but updates work
// without these changes
Method mCreateTheme = AssetManager.class.getDeclaredMethod("createTheme");
mCreateTheme.setAccessible(true);
Object internalTheme = mCreateTheme.invoke(newAssetManager);
Field mTheme = Resources.Theme.class.getDeclaredField("mTheme");
mTheme.setAccessible(true);
mTheme.set(theme, internalTheme);
}
} catch (Throwable e) {
Log.e(LOG_TAG, "Failed to update existing theme for activity " + activity, e);
}
/**
* Step 7
*
* 调用 pruneResourceCaches(@NonNull Object resources) 方法去删除 资源缓存
*/
pruneResourceCaches(resources);
}
}
/**
* Step 8
*
* 1. 如果 > 4.4,反射拿到 ResourcesManager 的 getInstance 方法。获取 ResourcesManager 的单例对象,
* 有两种选择:
* 1.1 反射获取 mActiveResources Field,强转为 ArrayMap<?, WeakReference<Resources>> 类型,赋值给 references
* 1.2 反射获取 mResourceReferences Field,强转为 Collection<WeakReference<Resources>> 类型,赋值给 references
*
* 2. 如果 <= 4.4,通过 getActivityThread 方法去获取进程中的 ActivityThread 实例。 然后反射
* 获取 ActivityThread 的 mActiveResources Field,强转为 HashMap<?, WeakReference<Resources>> 类型,赋值给 references
*
* 3. 将 1 or 2 环境中,保存下来的 references 进行遍历,拿到每一个 WeakReference<Resources>
* 有两种选择:
* 3.1 Hook Resource 的 mAssets Field 的值为 补丁 AssetManager
* 3.2 如果 3.1 失败被 catch 了,反射拿到 Resource mResourcesImpl Field( ResourcesImpl )
* 然后 Hook ResourcesImpl 的 mAssets Field 的值为 补丁 AssetManager
*/
// Iterate over all known Resources objects
Collection<WeakReference<Resources>> references;
if (SDK_INT >= KITKAT) {
// Find the singleton instance of ResourcesManager
Class<?> resourcesManagerClass = Class.forName("android.app.ResourcesManager");
Method mGetInstance = resourcesManagerClass.getDeclaredMethod("getInstance");
mGetInstance.setAccessible(true);
Object resourcesManager = mGetInstance.invoke(null);
try {
Field fMActiveResources = resourcesManagerClass.getDeclaredField("mActiveResources");
fMActiveResources.setAccessible(true);
@SuppressWarnings("unchecked") ArrayMap<?, WeakReference<Resources>> arrayMap = (ArrayMap<?, WeakReference<Resources>>) fMActiveResources.get(resourcesManager);
references = arrayMap.values();
} catch (NoSuchFieldException ignore) {
Field mResourceReferences = resourcesManagerClass.getDeclaredField("mResourceReferences");
mResourceReferences.setAccessible(true);
// noinspection unchecked
references = (Collection<WeakReference<Resources>>) mResourceReferences.get(resourcesManager);
}
} else {
Class<?> activityThread = Class.forName("android.app.ActivityThread");
Field fMActiveResources = activityThread.getDeclaredField("mActiveResources");
fMActiveResources.setAccessible(true);
Object thread = getActivityThread(context, activityThread);
@SuppressWarnings("unchecked") HashMap<?, WeakReference<Resources>> map = (HashMap<?, WeakReference<Resources>>) fMActiveResources.get(thread);
references = map.values();
}
for (WeakReference<Resources> wr : references) {
Resources resources = wr.get();
if (resources != null) {
// Set the AssetManager of the Resources instance to our brand new one
try {
Field mAssets = Resources.class.getDeclaredField("mAssets");
mAssets.setAccessible(true);
mAssets.set(resources, newAssetManager);
} catch (Throwable ignore) {
Field mResourcesImpl = Resources.class.getDeclaredField("mResourcesImpl");
mResourcesImpl.setAccessible(true);
Object resourceImpl = mResourcesImpl.get(resources);
Field implAssets = resourceImpl.getClass().getDeclaredField("mAssets");
implAssets.setAccessible(true);
implAssets.set(resourceImpl, newAssetManager);
}
resources.updateConfiguration(resources.getConfiguration(), resources.getDisplayMetrics());
}
}
} catch (Throwable e) {
throw new IllegalStateException(e);
}
}
use of android.content.res.AssetManager in project AndroidLife by CaMnter.
the class AssetsUtils method extractAssets.
/**
* 把 Assets 里面得文件复制到 /data/data/files 目录下
*
* @param context context
* @param sourceName sourceName
*/
public static void extractAssets(@NonNull final Context context, @NonNull final String sourceName) {
AssetManager assetManager = context.getAssets();
InputStream is = null;
FileOutputStream fos = null;
try {
is = assetManager.open(sourceName);
File extractFile = context.getFileStreamPath(sourceName);
fos = new FileOutputStream(extractFile);
byte[] buffer = new byte[1024];
int count;
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSilently(is);
closeSilently(fos);
}
}
use of android.content.res.AssetManager in project AndroidLife by CaMnter.
the class AssetsUtils method extractAssets.
/**
* 把 Assets 里面得文件复制到 /data/data/files 目录下
*
* @param context context
* @param sourceName sourceName
*/
public static void extractAssets(@NonNull final Context context, @NonNull final String sourceName) {
AssetManager assetManager = context.getAssets();
InputStream is = null;
FileOutputStream fos = null;
try {
is = assetManager.open(sourceName);
File extractFile = context.getFileStreamPath(sourceName);
fos = new FileOutputStream(extractFile);
byte[] buffer = new byte[1024];
int count;
while ((count = is.read(buffer)) > 0) {
fos.write(buffer, 0, count);
}
fos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
closeSilently(is);
closeSilently(fos);
}
}
Aggregations