给定 VectorDrawable 的字节数组,如何从中创建 VectorDrawable 的实例? [英] Given byte-array of VectorDrawable, how can I create an instance of VectorDrawable from it?

查看:22
本文介绍了给定 VectorDrawable 的字节数组,如何从中创建 VectorDrawable 的实例?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我的应用在设备的存储,显示有关它们的信息并允许对它们执行操作.

My app finds APK files in the storage of the device, showing information about them and allowing to perform operations on them.

事情是,自从谷歌增加了关于存储的新限制,我试图找到关于如何在没有存储许可的情况下解析 APK 文件的解决方案(因为框架只能处理文件路径).现在我使用 特殊遗留标志(requestLegacyExternalStorage) 到 允许我使用文件路径来做这件事,但它是下一个 Android 版本之前的临时解决方案.

Thing is, ever since Google added new restrictions about storage, I'm trying to find solutions about how to parse APK files without storage permission (because the framework can handle only file-path). For now I use the special legacy flag (requestLegacyExternalStorage) to allow me to do it with file-path, but it's a temporary solution till the next version of Android.

目前,使用 解决方法(链接这里),我成功获取了基本信息和应用程序名称,但是对于图标,它变得混乱:错误的限定符,可以返回 PNG 而不是 VectorDrawable,而 VectorDrawable 只是一个字节数组...

Currently, using a workaround and a the library (link here), I succeeded getting the basic information and the app name, but for icons it becomes messy : wrong qualifiers, can return PNG instead of VectorDrawable, and the VectorDrawable is just a byte array...

但即使我忽略了它的问题,我也尝试查看各种 VectorDrawable 函数以及它的 android-x 函数(实际上 看起来很有前途),尝试用我得到的东西创建一个实例.出于某种原因,我尝试的每个功能都没有帮助.

But even if I ignore its issues, I tried to look at the various VectorDrawable functions and also its android-x ones (which actually looked very promising), to try to create an instance out of what I got. For some reason, each function I tried didn't help.

是否可以从字节码动态加载 VectorDrawable?现在我打算使用 这个库,它自己解析 APK(因为可悲的是谷歌计划添加访问文件的限制,以使用可怕的 SAF),但遗憾的是 VectorDrawable 它只有一个字节数组...

Is it possible to load VectorDrawable dynamically from byte code? For now I'm planning to use this library which parses APKs on its own (because sadly Google is planning to add restrictions of reaching files, to use the terrible SAF), but sadly for VectorDrawable it just has a byte array...

澄清一下:我说的是从 SAF 访问 APK 文件(不是已安装的文件,因为获取此信息仍然可以正常工作).有了存储权限,它就可以正常工作(当然还有安装的应用程序).请参阅此处.当您尝试将 SAF 与普通框架一起使用时,您会得到不好的结果:一个字符串,包名作为应用程序名称,默认图标作为应用程序图标(或更糟糕的是:异常).另请注意:我知道我可以将文件复制到我自己的应用程序的存储并仅使用框架,但这不是一个好的解决方案,因为如果我想显示有关设备上所有 APK 文件的信息,那将是一种浪费空间和时间,只是为了获得图标和应用程序名称......我需要一个更直接的方法.应用处理速度最快的一种.

Just to be clear: I'm talking about accessing the APK files (not installed ones, as getting this information still works fine) from SAF. With storage permission it worked fine (and of course with installed apps). See here. When you try to use SAF with the normal framework, you will get bad results: a string with a package name as the app-name, and the default icon as the app-icon (or worse: an exception). Also note: I know I can copy the files to my own app's storage and use just the framework, but this isn't a good solution, because if I want to show information about all APK files on the device, it would be a waste of space and time, just to get the icons and app-names... I need a more direct approach. One that is fastest for the app to handle.

推荐答案

如果您拥有的 vector drawable 的字节数组具有二进制 XML 形式,那么您应该可以通过将数组传递给以下方法来创建它 I取自我的之前的答案:

If the byte array of the vector drawable you have has a binary XML form, then you should be able to create it by passing the array to the following method I took from my previous answer:

/**
 * Create a vector drawable from a binary XML byte array.
 * @param context Any context.
 * @param binXml Byte array containing the binary XML.
 * @return The vector drawable or null it couldn't be created.
 */
public static Drawable getVectorDrawable(@NonNull Context context, @NonNull byte[] binXml) {
    try {
        // Get the binary XML parser (XmlBlock.Parser) and use it to create the drawable
        // This is the equivalent of what AssetManager#getXml() does
        @SuppressLint("PrivateApi")
        Class<?> xmlBlock = Class.forName("android.content.res.XmlBlock");
        Constructor xmlBlockConstr = xmlBlock.getConstructor(byte[].class);
        Method xmlParserNew = xmlBlock.getDeclaredMethod("newParser");
        xmlBlockConstr.setAccessible(true);
        xmlParserNew.setAccessible(true);
        XmlPullParser parser = (XmlPullParser) xmlParserNew.invoke(
                xmlBlockConstr.newInstance((Object) binXml));

        if (Build.VERSION.SDK_INT >= 24) {
            return Drawable.createFromXml(context.getResources(), parser);
        } else {
            // Before API 24, vector drawables aren't rendered correctly without compat lib
            final AttributeSet attrs = Xml.asAttributeSet(parser);
            int type = parser.next();
            while (type != XmlPullParser.START_TAG) {
                type = parser.next();
            }
            return VectorDrawableCompat.createFromXmlInner(context.getResources(), parser, attrs, null);
        }

    } catch (Exception e) {
        Log.e(TAG, "Vector creation failed", e);
    }
    return null;
}

我还没有测试过它,但如果您的字节数组确实是可绘制矢量的二进制 XML(这就是 XmlPullParserVectorDrawable 需要解析.

I haven't tested it but I don't see a reason why it shouldn't work if your byte array really is the binary XML of a vector drawable, which is what the XmlPullParser and VectorDrawable expects to parse.

我尝试使用 XmlPullParser 创建可绘制对象,如下所示:

I tried using XmlPullParser to create the drawable like this:

val xml = """
|<vector xmlns:android="http://schemas.android.com/apk/res/android"
|    android:width="24dp"
|    android:height="24dp"
|    android:viewportWidth="24.0"
|    android:viewportHeight="24.0">
|    <path
|        android:pathData="M9.5,3A6.5,6.5 0,0 0,3 9.5A6.5,6.5 0,0 0,9.5 16A6.5,6.5 0,0 0,13.33 14.744L18.586,20L20,18.586L14.742,13.328A6.5,6.5 0,0 0,16 9.5A6.5,6.5 0,0 0,9.5 3zM9.5,5A4.5,4.5 0,0 1,14 9.5A4.5,4.5 0,0 1,9.5 14A4.5,4.5 0,0 1,5 9.5A4.5,4.5 0,0 1,9.5 5z"
|        android:fillColor="#000000"/>
|</vector>
""".trimMargin()

val parser = XmlPullParserFactory.newInstance().newPullParser()
parser.setInput(xml.reader())

val drawable = Drawable.createFromXml(resources, parser, theme)
iconView.setImageDrawable(drawable)

但是这会失败并出现异常:java.lang.ClassCastException:android.util.XmlPullAttributes 不能转换为 android.content.res.XmlBlock$Parser.所以这毕竟不可能回答你的评论.

However this fails with an exception: java.lang.ClassCastException: android.util.XmlPullAttributes cannot be cast to android.content.res.XmlBlock$Parser. So this is not possible after all to answer your comment.

这篇关于给定 VectorDrawable 的字节数组,如何从中创建 VectorDrawable 的实例?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆