Search in sources :

Example 86 with AssetManager

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();
    }
}
Also used : AssetManager(android.content.res.AssetManager) HashMap(java.util.HashMap) Activity(android.app.Activity) ArrayMap(android.util.ArrayMap) Method(java.lang.reflect.Method) Field(java.lang.reflect.Field) WeakReference(java.lang.ref.WeakReference) Collection(java.util.Collection) Resources(android.content.res.Resources)

Example 87 with AssetManager

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;
}
Also used : Bitmap(android.graphics.Bitmap) AssetManager(android.content.res.AssetManager) InputStream(java.io.InputStream) IOException(java.io.IOException)

Example 88 with AssetManager

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);
    }
}
Also used : AssetManager(android.content.res.AssetManager) HashMap(java.util.HashMap) Activity(android.app.Activity) ArrayMap(android.util.ArrayMap) Method(java.lang.reflect.Method) Field(java.lang.reflect.Field) WeakReference(java.lang.ref.WeakReference) Collection(java.util.Collection) Resources(android.content.res.Resources)

Example 89 with AssetManager

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);
    }
}
Also used : AssetManager(android.content.res.AssetManager) InputStream(java.io.InputStream) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) File(java.io.File)

Example 90 with AssetManager

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);
    }
}
Also used : AssetManager(android.content.res.AssetManager) InputStream(java.io.InputStream) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) File(java.io.File)

Aggregations

AssetManager (android.content.res.AssetManager)346 IOException (java.io.IOException)141 InputStream (java.io.InputStream)121 Resources (android.content.res.Resources)75 File (java.io.File)54 FileOutputStream (java.io.FileOutputStream)34 XmlResourceParser (android.content.res.XmlResourceParser)32 DisplayMetrics (android.util.DisplayMetrics)31 Bitmap (android.graphics.Bitmap)23 Configuration (android.content.res.Configuration)21 BufferedReader (java.io.BufferedReader)21 InputStreamReader (java.io.InputStreamReader)20 ArrayList (java.util.ArrayList)20 FileInputStream (java.io.FileInputStream)18 OutputStream (java.io.OutputStream)17 Context (android.content.Context)16 Intent (android.content.Intent)16 JsonParser (com.google.gson.JsonParser)16 ByteArrayInputStream (java.io.ByteArrayInputStream)16 Method (java.lang.reflect.Method)16