代码之家  ›  专栏  ›  技术社区  ›  android developer

给定VectorDrawable的字节数组,如何从中创建VectorDrawable的实例?

  •  0
  • android developer  · 技术社区  · 6 年前

    My app 在设备的存储器中查找APK文件,显示有关它们的信息并允许对它们执行操作。

    问题

    事情是,自从Google增加了关于存储的新限制之后,我一直在尝试寻找解决方案,如何在没有存储权限的情况下解析APK文件(因为框架只能处理文件路径)。现在我用 special legacy flag (requestLegacyExternalStorage)到 allow me 但这是一个临时解决方案,直到下一个版本的Android。

    我尝试和发现的

    当前,使用 workaround 还有一个 library (链接 here ),我成功地获得了基本信息和应用程序名,但对于图标来说却变得一团糟:限定符错误,可以返回PNG而不是VectorDrawable,而VectorDrawable只是一个字节数组。。。

    但即使我忽略了它的问题,我还是试着去看看各种VectorDrawable函数以及它的android-x函数(实际上 looked very promising ),尝试根据我得到的创建一个实例。由于某种原因,我尝试的每个功能都没有帮助。

    问题

    是否可以从字节码动态加载VectorDrawable?现在我打算用 this library

    我想说的是从SAF访问APK文件(不是已安装的文件,因为获取这些信息仍然可以正常工作)。有了存储许可,它工作得很好(当然也包括安装的应用程序)。看到了吗 here . 当您尝试在普通框架中使用SAF时,您将得到错误的结果:一个字符串将包名称作为应用程序名称,而默认图标作为应用程序图标(或者更糟的情况是:异常)。 另请注意:我知道我可以将文件复制到我自己的应用程序的存储中,只使用框架,但这不是一个好的解决方案,因为如果我想显示设备上所有APK文件的信息,这将是浪费空间和时间,只是为了获取图标和应用程序名称。。。我需要一个更直接的方法。一个最快的应用程序处理。

    0 回复  |  直到 6 年前
        1
  •  1
  •   Nicolas    6 年前

    如果vector drawable的字节数组是二进制XML格式,那么您应该能够通过将数组传递给以下方法来创建它 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;
    }
    

    我还没有测试过它,但是如果你的字节数组真的是一个向量drawable的二进制XML,我不知道为什么它不能工作,这就是 XmlPullParser VectorDrawable

    我尝试使用XmlPullParser创建drawable,如下所示:

    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$分析器。所以这毕竟不可能回答你的评论。