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

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

问题描述

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

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

自从Google添加了有关存储的新限制以来,我一直在寻找有关如何在未经存储许可的情况下解析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(因为Google很遗憾计划增加访问文件的限制,以使用可怕的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时,会得到不好的结果:一个字符串,其中包名称为app-name,默认图标为app-icon(或更糟糕的是:一个异常). 另请注意:我知道我可以将文件复制到我自己的应用程序的存储中并仅使用框架,但这不是一个好的解决方案,因为如果我想在设备上显示有关所有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.

推荐答案

如果向量drawable的字节数组具有二进制XML形式,那么您应该能够通过将数组传递给以下方法来创建它:取自我的上一个答案:

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天全站免登陆