Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
567 views
in Technique[技术] by (71.8m points)

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

Background (背景)

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

(我的应用程序在设备存储中找到APK文件,显示有关它们的信息并允许对其执行操作。)

The problem (问题)

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).

(事实是,自从Google添加了有关存储的新限制以来,我一直在寻找有关如何在未经存储许可的情况下解析APK文件的解决方案(因为该框架只能处理文件路径)。)

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.

(现在,我使用特殊的旧式标志 (requestLegacyExternalStorage) 允许我使用文件路径来执行此操作,但这是在下一版Android之前的临时解决方案。)

What I've tried and found (我尝试过的发现)

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...

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

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.

(但是,即使我忽略了它的问题,我也尝试着查看各种VectorDrawable函数以及它的android-x函数(实际上看起来非常有前途 ),试图根据自己的能力创建一个实例。)

For some reason, each function I tried didn't help.

(由于某种原因,我尝试的每个功能都无济于事。)

The question (问题)

Is it possible to load VectorDrawable dynamically from byte code?

(是否可以从字节码动态加载VectorDrawable?)

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...

(目前,我正计划使用该库自行解析APK(因为可悲的是Google计划增加对文件的访问限制,以使用可怕的SAF),但可悲的是,对于VectorDrawable来说,它只有一个字节数组...)

Just to be clear: I'm talking about accessing the APK files (not installed ones, as getting this information still works fine) from SAF.

(明确说明:我说的是从SAF访问APK文件(未安装文件,因为获取此信息仍然可以正常工作)。)

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).

(当您尝试在常规框架中使用SAF时,会得到不好的结果:一个字符串,其中包名称为app-name,默认图标为app-icon(或更糟糕的是:一个异常)。)

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.

(另请注意:我知道我可以将文件复制到我自己的应用程序的存储中并仅使用框架,但这不是一个好的解决方案,因为如果我想在设备上显示有关所有APK文件的信息,那将是浪费时间和空间,只是为了获得图标和应用程序名称...我需要一种更直接的方法。)

One that is fastest for the app to handle.

(应用处理最快的一种。)

  ask by android developer translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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 :

(如果您可以绘制的向量vector的字节数组具有二进制XML形式,那么您应该可以通过将数组传递给我从上一个答案中获取的以下方法来创建它:)

/**
 * 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;
}

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.

(我还没有测试过,但是我不明白为什么如果您的字节数组确实是矢量可绘制对象的二进制XML,它不起作用的原因,这就是XmlPullParserVectorDrawable希望解析的。)

EDIT: I tried using XmlPullParser to create the drawable like this:

(编辑:我尝试使用XmlPullParser创建像这样的可绘制对象:)

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)

However this fails with an exception: java.lang.ClassCastException: android.util.XmlPullAttributes cannot be cast to android.content.res.XmlBlock$Parser.

(但是,此操作失败,并出现以下异常:java.lang.ClassCastException:android.util.XmlPullAttributes无法转换为android.content.res.XmlBlock $ Parser。)

So this is not possible after all to answer your comment.

(因此,这根本不可能回答您的评论。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...