首页 > 其他分享 >【MyAndroid】AndroidManifest.xml合并规则详解和注意事项

【MyAndroid】AndroidManifest.xml合并规则详解和注意事项

时间:2023-09-19 11:32:06浏览次数:38  
标签:xml MyAndroid 优先级 元素 合并 清单 AndroidManifest android 属性


APK 或 Android App Bundle 文件只能包含一个 AndroidManifest.xml 文件,但 Android Studio 项目可以包含多个清单文件,这些清单文件由主源代码集、build 变体和导入的库提供。因此,在构建应用时,Gradle 构建系统会将所有清单文件合并成一个清单文件打包到应用中。

清单合并工具遵循某些合并启发法和您使用特殊 XML 属性定义的合并偏好设置,来将各个清单文件中的所有 XML 元素组合在一起。本页介绍清单合并的运作方式以及如何应用合并偏好设置解决合并冲突。

合并优先级

合并工具会根据每个清单文件的优先级按顺序合并,将所有清单文件组合到一个文件中。例如,如果您有三个清单文件,则会先将优先级最低的清单合并到优先级第二高的清单中,然后再将合并后的清单合并到优先级最高的清单中,如图 1 所示。

【MyAndroid】AndroidManifest.xml合并规则详解和注意事项_android


图 1. 合并三个清单文件的流程,从优先级最低的清单文件(左)合并到优先级最高的清单文件(右)中

有三种基本的清单文件可以互相合并,它们的合并优先级如下(按优先级由高到低的顺序):

构建变体的清单文件

如果变体有多个源代码集,则其清单优先级如下:

构建变体清单(如 src/demoDebug/)
构建类型清单(如 src/debug/)
产品变种清单(如 src/demo/)
如果您使用的是变种维度,则清单优先级与每个维度在 flavorDimensions 属性中的列示顺序(按优先级由高到低的顺序)对应。

应用模块的主清单文件
所包含的库中的清单文件
如果您有多个库,则其清单优先级与依赖顺序(库出现在 Gradle dependencies 代码块中的顺序)一致。

例如,先将库清单合并到主清单中,然后再将主清单合并到 build 变体清单中。注意:这些合并优先级对所有源代码集都相同,如使用源代码集构建中所述。

合并冲突启发法

合并工具可以在逻辑上将一个清单中的每个 XML 元素与另一个清单中的对应元素相匹配。(如需详细了解匹配的工作原理,请参阅合并政策)。

如果优先级较低的清单中的某个元素与优先级较高的清单中的所有元素都不匹配,则会将该元素添加到合并后的清单中。不过,如果有匹配的元素,则合并工具会尝试将每个元素的所有属性组合到同一元素中。如果该工具发现两个清单包含相同的属性,但值不同,就会发生合并冲突。

表 1 描述了合并工具尝试将所有属性组合到同一元素中时可能出现的结果。

表 1. 属性值的默认合并行为

高优先级属性		低优先级属性		属性的合并结果
没有值			没有值			没有值(使用默认值)
				值 B			值 B
值 A			没有值			值 A
				值 A			值 A
				值 B			冲突错误 - 您必须添加合并规则标记

不过,在某些情况下,合并工具会采取其他行为方式以避免合并冲突:
元素中的属性绝不会合并在一起,只会使用优先级最高的清单中的属性。
和 元素中的 android:required 属性使用 OR 合并,这样一来,如果发生冲突,系统将应用 “true” 并始终包含一个清单所需的功能或库。
元素中的属性始终使用优先级较高的清单中的值,但以下情况除外:
如果优先级较低的清单中的 minSdkVersion 值较高,那么除非您应用 overrideLibrary 合并规则,否则将会发生错误。
如果优先级较低的清单中的 targetSdkVersion 值较低,合并工具将使用优先级较高的清单中的值,但也会添加所有必要的系统权限,以确保所导入的库继续正常运作(以防遇到较高的 Android 版本具有更多权限限制的情况)。如需详细了解此行为,请参阅有关隐式系统权限的部分。
绝不会在清单之间匹配 元素。每个该元素都被视为唯一的元素,并添加到合并后的清单中的共同父元素中。
对于属性之间的其他所有冲突,您将收到一条错误,并且必须指示合并工具如何解决该错误,方法是在优先级较高的清单文件中添加一个特殊属性(请参阅下面有关合并规则标记的部分)。

合并规则标记

合并规则标记是一个 XML 属性,可用于指定您对如何解决合并冲突或移除不需要的元素和属性的偏好。您可以对整个元素应用标记,也可以只对元素中的特定属性应用标记。

合并两个清单文件时,合并工具会在优先级较高的清单文件中查找这些标记。

所有标记都属于 Android tools 命名空间,因此您必须先在 元素中声明此命名空间,如下所示:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.myapp"
    xmlns:tools="http://schemas.android.com/tools">

节点标记
如需对整个 XML 元素(给定清单元素中的所有属性及其所有子标记)应用合并规则,请使用以下属性:

tools:node=“merge”

在没有冲突的情况下,使用合并冲突启发法合并此标记中的所有属性以及所有嵌套元素。这是元素的默认行为。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge">
</activity>

合并后的清单结果:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

tools:node=“merge-only-attributes”

仅合并此标记中的属性,不合并嵌套元素。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <data android:type="image/*" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="merge-only-attributes">
</activity>

合并后的清单结果

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">
</activity>

tools:node=“remove”

从合并后的清单中移除此元素。虽然您似乎只需要删除此元素即可,但如果您发现合并后的清单中有不需要的元素,而且该元素是由不受您控制的优先级较低的清单文件(如导入的库)提供的,则必须使用此属性。
低优先级清单:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

高优先级清单:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      tools:node="remove"/>
</activity-alias>

合并后的清单结果:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

tools:node=“removeAll”

与 tools:node=“remove” 类似,但它会移除与此元素类型匹配的所有元素(同一父元素内)。
低优先级清单

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

高优先级清单:

<activity-alias android:name="com.example.alias">
  <meta-data tools:node="removeAll"/>
</activity-alias>

合并后的清单结果:

<activity-alias android:name="com.example.alias">
</activity-alias>

tools:node=“replace”

完全替换优先级较低的元素。也就是说,如果优先级较低的清单中有匹配的元素,会将其忽略并完全按照此元素在此清单中显示的样子使用它。
低优先级清单

<activity-alias android:name="com.example.alias">
  <meta-data android:name="cow"
      android:value="@string/moo"/>
  <meta-data android:name="duck"
      android:value="@string/quack"/>
</activity-alias>

高优先级清单:

<activity-alias android:name="com.example.alias"
    tools:node="replace">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

合并后的清单结果:

<activity-alias android:name="com.example.alias">
  <meta-data android:name="fox"
      android:value="@string/dingeringeding"/>
</activity-alias>

tools:node=“strict”

每当此元素在优先级较低的清单中与在优先级较高的清单中不完全匹配时,都会导致构建失败(除非已通过其他合并规则标记解决)。这会替换合并冲突启发式算法。例如,如果优先级较低的清单只是包含一个额外的属性,构建就会失败(尽管默认行为是将该额外属性添加到合并后的清单中)。
低优先级清单

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">
    <intent-filter>
        <action android:name="android.intent.action.SEND" />
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:node="strict">
</activity>

这会导致清单合并错误。在严格模式下,这两个清单元素不能有任何不同。因此,您必须应用其他合并规则标记解决这些差异。(通常,这两个元素会正常合并在一起,如上面的 tools:node=“merge” 示例中所示。)

属性标记

如需只对清单标记中的特定属性应用合并规则,请使用以下属性。每个属性可接受一个或多个属性名称(包括属性命名空间)

tools:remove=“attr, …”

从合并后的清单中移除指定属性。虽然您似乎只需要删除这些属性即可,但如果优先级较低的清单文件包含这些属性,而您想确保它们不会被纳入合并后的清单,则必须使用此属性。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:windowSoftInputMode="stateUnchanged">

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:remove="android:windowSoftInputMode">

合并后的清单结果

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait">

tools:replace=“attr, …”

将优先级较低的清单中的指定属性替换为此清单中的属性。换句话说,始终保留优先级较高的清单中的值。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:windowSoftInputMode="stateUnchanged">

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported">

合并后的清单结果

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    android:windowSoftInputMode="stateUnchanged">

tools:strict=“attr, …”

每当这些属性在优先级较低的清单中与在优先级较高的清单中不完全匹配时,都会导致构建失败。这是所有属性的默认行为,但具有特殊行为的属性除外,如合并冲突启发法中所述。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="landscape">
</activity>

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:screenOrientation="portrait"
    tools:strict="android:screenOrientation">
</activity>

这会导致清单合并错误。您必须应用其他合并规则标记解决冲突。(切记:这是默认行为,因此如果您移除 tools:strict=“screenOrientation”,上面的示例将具有相同的结果。)

您也可以对一个元素应用多个标记,如下所示。
低优先级清单:

<activity android:name="com.example.ActivityOne"
    android:theme="@oldtheme"
    android:exported="false"
    android:allowTaskReparenting="true"
    android:windowSoftInputMode="stateUnchanged">

高优先级清单:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:screenOrientation="portrait"
    tools:replace="android:theme,android:exported"
    tools:remove="android:windowSoftInputMode">

合并后的清单结果:

<activity android:name="com.example.ActivityOne"
    android:theme="@newtheme"
    android:exported="true"
    android:allowTaskReparenting="true"
    android:screenOrientation="portrait">

标记选择器

如果您想只对导入的某个特定库应用合并规则标记,请添加带有库软件包名称的 tools:selector 属性。

例如,对于下面的清单,只有在优先级较低的清单文件来自 com.example.lib1 库时,才会应用 remove 合并规则。

<permission android:name="permissionOne"
    tools:node="remove"
    tools:selector="com.example.lib1">

如果优先级较低的清单来自其他任何来源,则会忽略 remove 合并规则。

替换导入的库的

默认情况下,导入 minSdkVersion 值高于主清单文件的库时会出错,而且无法导入该库。如需使合并工具忽略此冲突并导入库,同时保留应用的较低 minSdkVersion 值,请将 overrideLibrary 属性添加到 标记。属性值可以是一个或多个库软件包名称(用英文逗号分隔),指明可以替换主清单的 minSdkVersion 的库。

例如,如果应用的主清单按如下方式应用 overrideLibrary:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.app"
          xmlns:tools="http://schemas.android.com/tools">
  <uses-sdk tools:overrideLibrary="com.example.lib1, com.example.lib2"/>
...

则以下清单可以合并,而不会出现与 标记相关的错误,合并后的清单将保留应用清单中的 minSdkVersion=“2”。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="com.example.lib1">
   <uses-sdk android:minSdkVersion="4" />
...

隐式系统权限

一些曾经可由应用自由访问的 Android API 在最新的 Android 版本中受到了系统权限的限制。为了避免中断预期会访问这些 API 的应用,最新的 Android 版本允许应用在无权限的情况下继续访问这些 API,条件是它们将 targetSdkVersion 设为低于添加限制的版本的值。此行为会有效地向应用授予隐式权限,以允许它们访问这些 API。因此,这可能会对具有不同 targetSdkVersion 值的合并后的清单产生以下影响。

如果优先级较低的清单文件具有较低的 targetSdkVersion 值,因而为其提供了一项隐式权限,但优先级较高的清单不具备相同的隐式权限(因为它的 targetSdkVersion 等于或高于添加限制的版本),则合并工具会向合并后的清单明确添加相应的系统权限。

例如,如果您的应用将 targetSdkVersion 设为 4 或更高的值,但导入的库将 targetSdkVersion 设为 3 或更低的值,则合并工具会向合并后的清单添加 WRITE_EXTERNAL_STORAGE 权限。表 2 列出了可以向合并后的清单添加的所有可能的权限。

优先级较低的清单声明											向合并后的清单添加的权限
targetSdkVersion 为 3 或更低的值								WRITE_EXTERNAL_STORAGE、READ_PHONE_STATE
targetSdkVersion 为 15 或更低的值,并且使用 READ_CONTACTS		READ_CALL_LOG
targetSdkVersion 为 15 或更低的值,并且使用 WRITE_CONTACTS		WRITE_CALL_LOG

检查合并后的清单并查找冲突

甚至在您构建应用之前,就可以预览合并后的清单是什么样子,方法是在 Android Studio 中打开您的 AndroidManifest.xml 文件,然后点击编辑器底部的 Merged Manifest 标签页。

在“Merged Manifest”视图中,左侧会显示合并后的清单结果,右侧会显示所合并的每个清单文件的相关信息,如图 2 所示。从优先级较低的清单文件中合并的元素在左侧以不同的颜色突出显示。每种颜色的键在右侧的 Manifest Sources 下方指定。

【MyAndroid】AndroidManifest.xml合并规则详解和注意事项_gradle_02


属于 build 的一部分但未贡献元素或属性的清单文件列在右侧的 Other Manifest Files 下方。

如需查看有关元素来源的信息,只需在左侧点击相应元素,详细信息即会显示在右侧的 Merging Log 下方。

如果发生任何冲突,它们将显示在右侧的 Merging Errors 下方,并且包含有关如何使用合并规则标记解决冲突的建议。错误也会显示在 Event Log 窗口(依次选择 View > Tool Windows > Event Log)中。

如果您想要查看合并决策树的完整日志,可以在模块的 build/outputs/logs/ 目录中查找名为 manifest-merger-buildVariant-report.txt 的日志文件。

合并策略

清单合并工具可以在逻辑上将一个清单文件中的每个 XML 元素与另一个文件中的对应元素相匹配。合并工具会使用“匹配键”匹配每个元素,匹配键可以是唯一的属性值(如 android:name),也可以是标记本身的自然唯一性(例如,只能有一个 元素)。如果两个清单具有相同的 XML 元素,则该工具会采用三种合并政策中的一种,将这两个元素合并在一起:

合并
将所有没有冲突的属性组合到同一标记中,并按各自的合并政策合并子元素。如果任何属性相互冲突,则使用合并规则标记将它们合并在一起。
仅合并子元素
不组合或合并属性(仅保留优先级最高的清单文件提供的属性),并按各自的合并政策合并子元素。
保留
将元素“按原样”保留,并将其添加到合并后的文件中的共同父元素中。只有在可以接受同一元素有多个声明时,才会采用此政策。

元素						合并政策						匹配键
<action>				合并							android:name 属性
<activity>				合并							android:name 属性
<application>			合并							每个 <manifest> 只有一个
<category>				合并							android:name 属性
<data>					合并							每个 <intent-filter> 只有一个
<grant-uri-permission>	合并							每个 <provider> 只有一个
<instrumentation>		合并							android:name 属性
<intent-filter>			保留							不匹配;允许父元素内的多个声明
<manifest>				仅合并子元素					每个文件只有一个
<meta-data>				合并							android:name 属性
<path-permission>		合并							每个 <provider> 只有一个
<permission-group>		合并							android:name 属性
<permission>			合并							android:name 属性
<permission-tree>		合并							android:name 属性
<provider>				合并							android:name 属性
<receiver>				合并							android:name 属性
<screen>				合并							android:screenSize 属性
<service>				合并							android:name 属性
<supports-gl-texture>	合并							android:name 属性
<supports-screen>		合并							每个 <manifest> 只有一个
<uses-configuration>	合并							每个 <manifest> 只有一个
<uses-feature>			合并							android:name 属性(如果不存在,则使用 android:glEsVersion 属性)
<uses-library>			合并							android:name 属性
<uses-permission>		合并							android:name 属性
<uses-sdk>				合并							每个 <manifest> 只有一个
自定义元素				合并							不匹配;合并工具并不知晓这些元素,因此它们始终包含在合并后的清单中

将 build 变量注入清单

如果您需要将变量插入在 build.gradle 文件中定义的 AndroidManifest.xml 文件,可以使用 manifestPlaceholders 属性执行此操作。此属性采用键值对的映射,如下所示:

android {
    defaultConfig {
        manifestPlaceholders = [hostName:"www.example.com"]
    }
    ...
}

然后,您可以将某个占位符作为属性值插入清单文件,如下所示:

<intent-filter ... >
    <data android:scheme="https" android:host="${hostName}" ... />
    ...
</intent-filter>

默认情况下,构建工具还会在 ${applicationId} 占位符中提供应用的应用 ID。该值始终与当前构建的最终应用 ID(包括构建变体的应用 ID 更改)一致。当您要对标识符(如 intent 操作)使用唯一的命名空间时,这很有用,即使要求在构建变体之间保持唯一性,这也很有用。

例如,如果您的 build.gradle 文件如下所示:

android {
    defaultConfig {
        applicationId "com.example.myapp"
    }
    productFlavors {
        free {
            applicationIdSuffix ".free"
        }
        pro {
            applicationIdSuffix ".pro"
        }
    }
}

那么,您可以按如下方式在清单中插入应用 ID:

<intent-filter ... >
    <action android:name="${applicationId}.TRANSMOGRIFY" />
    ...
</intent-filter>

当您构建“free”产品变种时,清单结果如下所示:

<intent-filter ... >
   <action android:name="com.example.myapp.free.TRANSMOGRIFY" />
    ...
</intent-filter>

自研产品推荐

历时一年半多开发终于smartApi-v1.0.0版本在2023-09-15晚十点正式上线
smartApi是一款对标国外的postman的api调试开发工具,由于开发人力就作者一个所以人力有限,因此v1.0.0版本功能进行精简,大功能项有:

  • api参数填写
  • api请求响应数据展示
  • PDF形式的分享文档
  • Mock本地化解决方案
  • api列表数据本地化处理
  • 再加上UI方面的打磨

为了更好服务大家把之前的公众号和软件激活结合,如有疑问请大家反馈到公众号即可,下个版本30%以上的更新会来自公众号的反馈。

嗯!先解释不上服务端原因,API调试工具的绝大多数时候就是一个数据模型、数据处理、数据模型理解共识的问题解决工具,所以作者结合自己十多年开发使用的一些痛点来打造的,再加上服务端开发一般是面向企业的,作者目前没有精力和时间去打造企业服务。再加上没有资金投入所以服务端开发会滞后,至于什么时候会进行开发,这个要看募资情况和用户反馈综合考虑。虽然目前国内有些比较知名的api工具了,但作者使用后还是觉得和实际使用场景不符。如果有相关吐槽也可以在作者的公众号里反馈蛤!

下面是一段smartApi使用介绍:

【MyAndroid】AndroidManifest.xml合并规则详解和注意事项_android studio_03

下载地址:

https://pan.baidu.com/s/1kFAGbsFIk3dDR64NwM5y2A?pwd=csdn


标签:xml,MyAndroid,优先级,元素,合并,清单,AndroidManifest,android,属性
From: https://blog.51cto.com/u_16264967/7523894

相关文章

  • WEB漏洞-XXE&XML之利用检测绕过全解
    XML内容: <?xmlversion="1.0"?> <!DOCTYPEa[ <!ENTITY%dSYSTEM“file:///etc/passwd”>%d; ]> <c>%d;</c> XML内容 <?xmlversion=’1.0’?> <!DOCTYPEa[ <!ENTITY%dSYSTEM“http://abc.com/evil.dt......
  • 计划任务导入xml
     https://superuser.com/questions/1031539/create-schedule-task-from-xml-file-by-batch-fileschtasks.exe/create/sNAMEOFCOMPUTER/ruDOMAIN\USER/rpPASSWORD/tnNAMEOFTASK'/XMLPATHTOXMLFILE ......
  • FastAPI学习-18.Response 返回 XML 格式
    前言假设你想要返回一个 XML响应。你可以把你的XML内容放到一个字符串中,放到一个 Response 中,然后返回。Response自定义返回可以把XML内容放到一个字符串中,放到一个 Response 中,设置media_type="application/xml"fromfastapiimportFastAPI,Responseapp=Fa......
  • tomcat里web.xml中load-on-startup参数含义
    原文:Theload-on-startupelementindicatesthatthisservletshouldbeloaded(instantiatedandhaveitsinit()called)onthestartupofthewebapplication.Theoptionalcontentsoftheseelementmustbeanintegerindicatingtheorderinwhichtheserv......
  • 不小心把pom.xml文件变成了Ant类型,然后全面爆红问题的解决
    问题描述不小心按到了这里:导入依赖的文件这里就全面爆红了!!本来都要配置完成了,出现这个误操作,真的很崩心态!问题解决这么操作:文件目录-->Views-->ToolWindows-->Ant;就能够打开Ant的相关界面;然后右键选中想要操作的文件,选择Remove,就能解决啦!......
  • mavlink(二)xml文件结构
    1.xml文件框架和语法1.1.文件结构MaVLinkXML文件的大致结构如下:下面列出了主要标签(所有标签都是可选的):include:此标签用于指定语支文件(dialect)中包含的任何其他xml文件。通常,语支文件将includecommon.xml,如上所示;可以使用多个<include></include>标记,以......
  • c# XML 文档
    c#添加xml文档数据:1:引用命名空间System.Xml2:创建文档对象XmlDocument类3:创建描述信息XmlDeclaration类4:创建节点XmlElement类5:创建节点集合XmlNodeList类6:创建节点属性Xpath文档类:创建行描述信息:CreatXmlDeclaration(版本(必须为1.0),编码格式,独立特性与否(否为null))创......
  • XML学习笔记
    第三篇:学习xml之"实体"篇         xml包含的7大基础概念:   1、元素2、属性3、名称空间4、实体5、注释6、CDATA7、处理指令xml的七大基础概念中,实体算是最复杂的了,现在开始介绍实体:一、实体的作用:                        A、......
  • 【uniapp】【微信小程序】wxml-to-canvas
    真是搞吐了,研究了整整两天,困死我了 本来使用生成二维码插件好好的,插件页也支持导出二维码图片,可是领导说要带上文件的名称,那就涉及html转图片了,当然也可以改二维码插件的源码,不过源码做了混淆,看晕了,放弃了。试了将微信的原生插件wxml-to-canvas引入uniapp项目,最后捣鼓了好久没......
  • GIS中的ROI文件可否由.xml格式转为.roi格式?
      本文介绍在ENVI软件中,将用户自行绘制的.xml格式的感兴趣区(ROI)文件转换为.roi格式的方法。  对于ENVI软件,其在早期版本中,默认将用户所绘制的感兴趣区文件保存为.roi格式;而在后期的软件版本中,则默认保存为.xml格式。  例如,以ENVI5.3软件为例——通过在图层列表中选择“Ne......