ant使用全总结_ant教程_ant打包apk_ant如何使用

所需文件ant打包apk需要三个目录: build.xml,local.properties,proguard-project.txt生成方式,在项目根目录下执行指令:android update project —path .其中,build.xml文件是进行ant build的主要文件,它引用了其它文件。这些被引用的文件有local.properties,ant.properties两个属性文

大家好,又见面了,我是全栈君。

项目一直用ant打包apk,没有自己写过ant配置文件,抽空总结了一下。

所需文件
ant打包apk需要三个目录:
 
build.xml,local.properties,proguard-project.txt
生成方式,在项目根目录下执行指令:
android update project path .

其中,build.xml文件是进行ant build的主要文件,它引用了其它文件。
这些被引用的文件有local.properties,ant.properties两个属性文件,
以及在build.xml中的最后,引用了sdk目录下的tools/ant/build.xml文件。

local.properties文件中定义了sdk.dir属性,也就是当前使用的sdk的目录。
ant.properties可根据构建需要进行相关配置。
项目下的build.xml默认执行的target是help,运行后可以看到相关的帮助信息。如果需要的话,我们可将其修改为debug或者release。
通过查看相关的帮助信息,可以看到其它可用的target。然后运行ant时,可指定target。例如,ant debug, ant help, ant relaese等等。

配置ant.properties 
ant.properties文件是不会自动生成的,需在项目根目录下新建一个ant.properties文件
然后根据构建的实际需要进行相关配置。在ant.properties文件中,可以定义自己的一些属性,或者重定义一些属性。

1、设定私钥库

ant构建时,如果是debug版的话,默认会使用debug方式签名。
如果是release版的话,需指定相应的keystore以及私钥。否则,最后只能生成一个没有签名的apk文件。
设定私钥库的方法如下:

在ant.properties文件中,添加如下内容:
key.store=<keystore>
key.alias=<key>
key.store.password=<keystore pwd>
key.alias.password=<key pwd>

其中:
keystore为私钥库文件。
key为签名需要使用的私钥。
key.store.password为私钥库的密码。
key.alias.password为私钥的密码。

2、如果项目引用了第三方库的话,只需要在项目根目录创建libs文件夹并将其放入即可。

如果是jar库,直接放到libs目录下;
如果是so库,需要放到libs的名为armeabi的子目录下。
也可以通过设定相应的属性来指定第三方库的位置,其默认都是libs文件夹。
jar.libs.dir为jar类型库所在的目录。
native.libs.absolute.dir为so类型库所在的目录,即armeabi的父目录。

3、如果项目包含了jni代码,希望在打包时自动重新编译so库,可以修改build.xml文件。
修改方法为,在引用sdk的build.xml文件之前添加如下target:

  <target name=”-pre-build” depends=”-ndk-build”>


  </target>


  <target name=”-ndk-build”>


      <exec executable=”ndk-build” failοnerrοr=”true”>


          <arg value=”clean” />


      </exec>


      <exec executable=”ndk-build” failοnerrοr=”true” />


  </target>


ndk-build为ndk提供的命令,需要将ndk安装目录添加到环境变量中,添加方法同sdk/tools。
生成的so默认会放到libs/armeabi目录下。
如果没有正确签名,使用ant release打包后无法安装,会报错INSTALL_PARSE_FAILED_NO_CERTIFICATES
平时可以ant debug打包运行。


ant文件详解

ant的默认生成文件为build.xml;输入ant后,ant会在当前目录下搜索是否有build.xml,如果有,则执行;当然也可以自定义生成文件,通过ant -f a.xml即可指定a.xml为生成文件;
ant的生成文件是xml文件,整体结构为:

?
1
2
3
4
5
<?
xml
version="1.0" encoding="GBK"?>
<
project
default=" targetname">
    
<
target
name="name">
    
</
target
>
</
project
>


project是生成文件的根元素,表示一个工程;

target是project的子元素,表示一个任务;一个project中可以定义多个target元素,表示多个任务;

default属性表示默认执行的target,如果ant命令没有指定target,则执行default的target;

ant targetname;则会执行此target,而忽略default设置的target;

注意:不能有两个相同的targetname;

代码举例:创建并删除hello目录;

?
1
2
3
4
5
6
7
8
9
10
<?
xml
version="1.0" encoding="gbk"?>
<
project
default="delete">
    
<
property
name="name" value="xiazdong"/>
    
<
target
name="delete" depends="mkdir">
        
<
delete
dir="${name}"/>
    
</
target
>
    
<
target
name="mkdir">
        
<
mkdir
dir="${name}"/>
    
</
target
>
</
project
>


1.<project>元素
是Ant生成文件的根元素;一般形式如:

<project default=“target”  basedir=”.”   name=”projectname”>
(1) default表示默认的运行目标,这个属性是必须的。 
(2) basedir表示项目的基准目录,一般都是basedir=”.”当前目录
。 
(3) name表示项目名。 
(4) description表示项目的描述。 

每个构建文件都对应于一个项目,但是大型项目经常包含大量的子项目,每一个子项目都可以有自己的构建文件。 



2.<target>元素
是project元素的子元素,在project元素中能够有多个target,一个target标签可以依赖其他的target标签。
例如,有一个target用于编译程序,另一个target用于生成可执行文件。在生成可执行文件之前必须先编译该文件,因此可执行文件的target依赖于编译程序的target。
一般形式如下:

<target name=” ”  depends=”A”   if =”prop1“  unless=”prop2”> 
</target>
(1) name表示名称,这个属性是必须的。 
(2) depends表示依赖的目标。 
(3) if表示仅当属性设置时才执行。 
(4) unless表示当属性没有设置时才执行。 
(5) description表示项目的描述。 

Ant的depends属性指定了target的执行顺序(可以有多个名称,用逗号分割)
。Ant会依照depends属性中target出现顺序依次执行每个target。在执行之前,首先需要执行它所依赖的target。程序中的名为run的target的depends属性compile,而名为compile的target的depends属性是prepare,所以这几个target执行的顺序是prepare->compile->run。一个target只能被执行一次,即使有多个target依赖于它。
if的值表示一个属性名,只有设置了该属性名,才能执行此target;
unless的值表示一个属性名,只有没有设置该属性名,才能执行此target;如果没有if或unless属性,target总会被执行。 



3.<property>元素
是project的子元素
用于定义属性,一般形如:

(1)<
property name=”pname”   value=”pvalue”/>

如果要使用此property,则需要${pname};类似于表达式语言;
(2)<property file=”a.properties”/>
 通过此属性文件导入属性;
如果单纯想使用$,则通过$$表示;



Task介绍
在Ant中Task是target的子元素,即一个target中可以有多个task;而Task分为:
(1)核心Task;
(2)可选Task;
(3)自定义Task;
下面介绍一些常用的核心Task;

1.<echo>
用于单纯输出,一般形如:

<echo>      </echo>
举例:<echo>hello</echo>


2.<javac>

用于编译java文件,一般形式如下:
<javac srcdir=”src”  destdir=”class”  classpath=”libs”/>;
(1).srcdir表示源程序的目录,
编译此文件夹下或子文件夹下的全部java文件
。 
(2).destdir表示class文件的输出目录,
编译后的class文件放置路径
。 
(3).include表示被编译的文件的模式,符合此模式的都会被编译。 
(4).excludes表示被排除的文件的模式,符合此模式的不会编译。 
(5).classpath表示所使用的类路径,指定第三方类库。 
(6).debug表示是否包含调试信息。 
(7).optimize表示是否使用优化。 
(8).verbose 表示提供详细的输出信息。 

(9).fileonerror表示当碰到错误就自动停止。 



3.<java>

用来执行编译生成的.class文件即运行java类,一般形式如下:

<java classname=” ”  fork=”yes“>

    <arg line=”param1   param2   param3″/>

</java>
(1).classname 表示将执行的类名。 

(2).jar表示包含该类的JAR文件名。 

(3).classpath所表示用到的类路径。 
(4).fork表示在一个新的虚拟机中运行该类,
而不是中断ANT命令,因此fork必须为yes;
(5).failonerror表示当出现错误时自动停止。 
(6).output 表示输出文件。 

(7).append表示追加或者覆盖默认文件。



4.<jar>
用来生成一个JAR文件把class打包成jar包;一般形式如下:

<jar destfile=”main.jar”  basedir=” “>

    <manifest>
        <attribute name=”Main-Class”   value=”classname”/>    <!–指定主类–>
    </manifest>
</jar>
destfiie的值为jar包的名称,一般为${dest}/main.jar

basedir的值是需要打成jar包的目录,一般为${classes}
manifest表示设置META-INF;
includes表示别归档的文件模式。 
excludes表示被排除的文件模式。 



5.<mkdir>

该标签用于创建一个目录,它有一个属性dir用来指定所创建的目录名,
其代码如下:<mkdir dir=”${class.root}”/>通过以上代码就创建了一个目录,这个目录已经被前面的property标签所指定。 

可以多层创建,比如a\b\c,则可以连续创建,形式如下:
<mkdir dir=”a\b”/>



6.<delete>

用于删除一个文件或一组文件,一般形式如下:

<delete dir=”a\b”/> 
可以删除a目录下的b目录;
<delete file=”1.txt”/>可以删除文件;
(1).file表示要删除的文件。 

(2).dir表示要删除的目录。 
(3).includeEmptyDirs 表示指定是否要删除空目录,默认值是删除。 
(4).failonerror 表示指定当碰到错误是否停止,默认值是自动停止。 

(5).verbose表示指定是否列出所删除的文件,默认值为不列出。 


7.<tstamp>

时间戳,一般形式如下:
<tstamp />
接下来可以使用${DSTAMP}进行调用当前时间;



8.<copy>

用于文件或文件集的拷贝
,一般形式如下:
<copy file=”file1″ tofile=”file2″/>
(1).file 表示源文件。 
(2).tofile 表示目标文件。 
(3).todir 表示目标目录。 
(4).overwrite 表示指定是否覆盖目标文件,默认值是不覆盖。 
(5).includeEmptyDirs 表示制定是否拷贝空目录,默认值为拷贝。 
(6).failonerror 表示指定如目标没有发现是否自动停止,默认值是停止。 

(7).verbose 表示制定是否显示详细信息,默认值不显示。



9.<move>

移动文件,一般形式如下:
<move file=”file1″ tofile=”file2″/>
file是源文件;
tofile是目标文件;



10.<replace>

用于替换字符串,类似于String的replace操作,一般形式如下:
<replace file=”filename” token=”old” value=”new”/>
file表示要执行替换的文件;
token表示被替换的字符串;
value表示替换的字符串;

 

代码举例:一般项目中的ant结构

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
<
project
default
=
"init"
>
    
<
property
name
=
"src"
value
=
"src"
/>
    
<
property
name
=
"classes"
value
=
"classes"
/>
    
<
property
name
=
"dest"
value
=
"dest"
/>
    
<
path
id
=
"classpath"
>
        
<
pathelement
path
=
"${classes}"
/>
    
</
path
>
    
<
target
name
=
"help"
>
        
<
echo
>help -打印帮助信息</
echo
>
        
<
echo
>compile -编译java源文件</
echo
>
        
<
echo
>run -运行程序</
echo
>
        
<
echo
>build -打成jar包</
echo
>
        
<
echo
>clean -清楚全部编译生成文件</
echo
>
    
</
target
>
    
<
target
name
=
"compile"
>
        
<
delete
dir
=
"${classes}"
/>
        
<
mkdir
dir
=
"${classes}"
/>
        
<
javac
srcdir
=
"${src}"
destdir
=
"${classes}"
/>
    
</
target
>
    
<
target
name
=
"run"
depends
=
"compile"
>
        
<
java
classname
=
"org.xiazdong.Test"
fork
=
"yes"
>
            
<
classpath
path
=
"${classes}"
/>
        
</
java
>
    
</
target
>
    
<
target
name
=
"build"
depends
=
"run"
>
        
<
delete
dir
=
"${dest}"
/>
        
<
mkdir
dir
=
"${dest}"
/>
        
<
jar
destfile
=
"${dest}/Test.jar"
basedir
=
"${classes}"
>
            
<
manifest
>
                
<
attribute
name
=
"Main-Class"
value
=
"org.xiazdong.Test"
/>
            
</
manifest
>
        
</
jar
>
    
</
target
>
    
<
target
name
=
"clean"
>
        
<
delete
dir
=
"${classes}"
/>
        
<
delete
dir
=
"${dest}"
/>
    
</
target
>
</
project
>

 

总结一下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?
xml
version

"1.0"
encoding
=
"GBK"
?>
<
project
name
=
"Test"
default
=
""
basedir
=
"."
>
    
<
property
name
=
"src"
value
=
"${basedir}\src"
/>
    
<
property
file
=
"${basedir}\a.properties"
/>
    
<!--
    
path用法
        
1.id属性表示编号,用于被引用
    
-->
    
<
path
id
=
"classpath"
>
    
<!-- 
    
pathelement的用法
        
1.path表示多个目录,用“;”隔开目录   
        
2.location表示一个目录
    
-->
        
<
pathelement
path
=
"lib;src"
/>
        
<
pathelement
location
=
"lib"
/>
    
<!--
    
dirset的用法
        
1.dir属性指定根目录
        
2.子元素<include name="    "/>表示包含的目录
        
3.子元素<exclude name="    "/>表示不包含的目录
    
-->
        
<
dirset
dir
=
"lib"
>
            
<
include
name
=
"**/*Test*"
/>
            
<
exclude
name
=
"**/class"
/>
        
</
dirset
>
    
<!--
    
filelist的用法
        
1.dir属性指定根路径
        
2.files属性指定文件名的列表,用","隔开
    
-->
        
<
filelist
dir
=
"lib"
files
=
"a.xml,b.xml"
/>
    
<!--
    
fileset用法
        
1.dir属性指出根路径
        
2.子元素<include name="   "/>指定包含的文件名
    
-->
        
<
fileset
dir
=
"lib"
>
            
<
include
name
=
"**/*.jar"
/>
        
</
fileset
>
    
</
path
>
    
<!--
    
target用法
        
1.表示任务,子元素为各种task的集合;
    
-->
    
<
target
name
=
"target1"
>
    
<!--
    
javac用法
        
1.srcdir表示java文件的目录
        
2.destdir表示class文件的保存目录
    
-->
        
<
javac
srcdir
=
"src"
destdir
=
"bin"
>
    
<!--
    
classpath用法
        
1.refid引用前面的path指定的路径
    
-->
            
<
classpath
refid
=
"classpath"
/>
        
</
javac
>
    
<!--
    
java用法
        
1.classname表示要运行的类
        
2.fork="yes"一定要写上!!
    
-->
        
<
java
classname
=
"Test"
fork
=
"yes"
>
            
<
classpath
refid
=
"classpath"
/>
    
<!--
        
arg表示指定的参数
    
-->
            
<
arg
value
=
"a b c"
/>
        
</
java
>
    
<!--
    
echo表示输出
    
-->
        
<
echo
>Hello world</
echo
>
    
<!--
    
copy表示复制文件
    
delete表示删除文件
    
mkdir表示创建目录
    
move表示移动文件
    
-->
        
<
copy
file
=
"src.txt"
tofile
=
"dest.txt"
/>
        
<
delete
dir
=
"src"
/>
        
<
mkdir
dir
=
"src"
/>
        
<
move
file
=
"src.txt"
tofile
=
"dest.txt"
/>
    
</
target
>
</
project
>



macrodef
macrodef的功能就类似于在程序中定义一个函数。这个函数可以指定参数,以及默认参数,同时也可以指定这个函数需要运行的一些任务。作用相当于java里面的为防止代码重复而提取的公共方法。比如我现在需要将某几个目录分别进行编译和打包,不使用MacroDef的情况下,如果有10个目录,那么我就至少要写10个类似的<target></target>来做完对这10个目录的操作;但在使用MacroDef的情况下,你只用写一个通用的<macrodef></macrodef>,再在其他地方调用它就可以了,既减少了代码量,又提高了工作效率。

一、由函数到macrodef

假设我们定义一个函数:

[python] 
view plain
copy

  1. def test (arg):  
  2.     to do something  

我们可以通过以下方法来执行这个方法

[python] 
view plain
copy

  1. test(‘test’)  

将这些移到ant中:

将to do something使用echo标签输出,然后使用<test/>调用这个宏。

[xml] 
view plain
copy

  1. <project name=“test_ant”>  
  2.          
  3.     <macrodef name=“test”>  
  4.         <attribute name=“arg” default=“testssss”/>  
  5.         <sequential>  
  6.             <echo>to do something</echo>  
  7.         </sequential>  
  8.     </macrodef>  
  9.     <test/>  
  10. </project>  

运行ant -f test.xml结果:

[bash] 
view plain
copy

  1. ———- ant ———-  
  2. Buildfile: D:\workspace\workspace20130318\Z_Frame\test.xml  
  3.      [echo] to do something  
  4.          
  5. BUILD SUCCESSFUL  
  6. Total time: 0 seconds  
  7.          
  8. 输出完成 (耗时 0 秒) – 正常终止  

标签macrodef:声明这是一个宏,name=”test”来告诉ant这个宏的名字叫做test。之后我们调用这个宏就可以使用</test>。

标签attribute:声明这个宏所需要的参数。

标签sequential:声明这个宏需要执行的实体。

二、传入参数

上面的例子中我们请求传入一个参数arg,并给这个arg设置了默认值”testssss”,接下来我们希望调用这个宏的时候传递这个参数,并且输出这个参数。如下:

[xml] 
view plain
copy

  1. <project name=“test_ant”>  
  2.     <macrodef name=“test”>  
  3.         <attribute name=“arg” default=“testssss”/>  
  4.         <sequential>  
  5.             <echo>arg is : @{arg}</echo>  
  6.         </sequential>  
  7.     </macrodef>  
  8.     <test arg=“i am a param”/>  
  9. </project>  

运行结果:

[bash] 
view plain
copy

  1. ———- ant ———-  
  2. Buildfile: D:\workspace\workspace20130318\Z_Frame\test.xml  
  3.      [echo] arg is : i am a param  
  4.          
  5. BUILD SUCCESSFUL  
  6. Total time: 0 seconds  
  7.          
  8. 输出完成 (耗时 0 秒) – 正常终止  

我们将arg作为test标签的属性名传入进入,而属性arg的内容就是arg的内容。我们通过@{参数}来调用这个参数的内容

三、调用一个声明的函数

假定我们希望我们的函数是这样的:

[python] 
view plain
copy

  1. def test (arg):  
  2.     print(arg)  
  3.          
  4. test(‘test’)  

也就是我们的会调用另一个函数print,这个在ant宏定义中是这样使用的:

[xml] 
view plain
copy

  1. <macrodef name=“test”>  
  2.     <attribute name=“arg” default=“testssss”/>  
  3.     <element name=“print” optional=“yes” />  
  4.     <sequential>  
  5.         <echo>arg is : @{arg}</echo>  
  6.         <print/>  
  7.     </sequential>  
  8. </macrodef>  

我们通过element函数来声明我们需要使用一个名字叫做print的函数。optional用来说明这个函数是否是必须存在的。也就是上面的程序加上element那一行是可以正常使用的。

尝试把optional改为no试试??自己试试吧。

我们这里声明了使用函数print,其实这是一个回调,为什么呢?一般来说我们会在<sequential>中使用这个函数。那么这个函数是需要在调用test的时候实现的。如果optional为no那么这个函数就是必须实现的,如果不实现是会报错的。如下:

[xml] 
view plain
copy

  1. <project name=“test_ant”>  
  2.          
  3.     <macrodef name=“test”>  
  4.         <attribute name=“arg” default=“testssss”/>  
  5.         <element name=“print” optional=“yes” />  
  6.         <sequential>  
  7.             <echo>arg is : @{arg}</echo>  
  8.             <print/>  
  9.         </sequential>  
  10.     </macrodef>  
  11.     <test arg=“i am a param”>  
  12.         <print>  
  13.             <echo>i am a function</echo>  
  14.         </print>  
  15.     </test>  
  16. </project>  

我们在调用test时通过一个标签对来实现了print函数。其实际的执行就是按照sequential的顺序执行:

首先输出:arg is : @{arg}

其次执行我们的 :print,当然我们的print存在的话。

[bash] 
view plain
copy

  1. ———- ant ———-  
  2. Buildfile: D:\workspace\workspace20130318\Z_Frame\test.xml  
  3.      [echo] arg is : i am a param  
  4.      [echo] i am a function  
  5.          
  6. BUILD SUCCESSFUL  
  7. Total time: 0 seconds  
  8.          
  9. 输出完成 (耗时 0 秒) – 正常终止  

Ok,编写个脚本试试吧!下面再给大家一个例子:

[xml] 
view plain
copy

  1. <project name=“test” default=“test”>  
  2.     <macrodef name=“print”>  
  3.         <attribute name=“text”/>  
  4.         <element name=“telement” optional=“yes” />  
  5.         <sequential>  
  6.             <echo>@{text}</echo>  
  7.         </sequential>  
  8.     </macrodef>  
  9.        
  10.     <macrodef name=“testing”>  
  11.        <attribute name=“v” default=“NOT SET”/>  
  12.        <!– 这里就相当于提供了一个接口 –>  
  13.        <element name=“some-tasks” optional=“yse”/>  
  14.        <sequential>  
  15.           <echo>v is @{v}</echo>  
  16.           <some-tasks/>  
  17.        </sequential>  
  18.     </macrodef>  
  19.        
  20.     <testing v=“This is v”>  
  21.        <some-tasks>  
  22.           <echo>this is a test</echo>  
  23.        </some-tasks>  
  24.     </testing>  
  25.        
  26.     <target name=“telement”>  
  27.         <print text=“telement”/>  
  28.     </target>  
  29.        
  30.     <target name=“test”>  
  31.         <print text=“print test”/>  
  32.     </target>  
  33. </project>  




通过macrodef可以减少代码重复

不使用MacroDef的情况下,编译和打包math和io等目录:

复制代码
<target name="build_math" depends="base">
    <echo message="... building jck-api-math-cases  now ..."/>
    <javac debug="false"  destdir="bin" source="1.5" target="1.5">
        <src path="./java_math"/>
        <classpath refid="java_jck.classpath"/>
    </javac>
</target>

<target name="make_math" depends="build_math">
    <echo message="... make math jar ...."></echo>
    <jar jarfile="math.jar" basedir="./bin"/>
    <move file="./math.jar" tofile="./lex/math.jar" overwrite="true"/>
</target>

<target name="build_io" depands="base">
    ……
</target>

<target name="make_io" depends="build_io">
    ……
</target>
……
复制代码

使用MacroDef的情况下,编译和打包math和io等目录:
———————————————————————————————————————

复制代码
<macrodef name="dealWithTestCases">            //macrodef的定义,定义了name属性
    <attribute name="tarName" />              //参数定义
    <attribute name="srcPath" />
    <!--element name="dex-elements"/-->
    <sequential>               //实际执行的内容在<sequential>里
        <echo message="... building jck-api-@{tarName}-cases  now ...."/>
        <javac debug="false"  destdir="bin" source="1.5" target="1.5" includeantruntime="on">
            <src path="./@{srcPath}"/>
            <classpath refid="java_jck.classpath"/>
            <excludesfile name="exclude.@{tarName}"/>
        </javac>
        <echo message="... make @{tarName} jar ..."></echo>
        <jar jarfile="@{tarName}.jar" basedir="./bin"/>
        <move file="./@{tarName}.jar" tofile="./lex/@{tarName}.jar" overwrite="true"/>
    </sequential>
</macrodef>

<target name="lex" depands="base">
    <dealWithTestCases tarName="math" srcPath="./java_math"/>     //外部调用宏
    <dealWithTestCases tarName="io" srcPath="./java_io"/>    
    ……    
</target>
复制代码


从例子中可以明显看出,MacroDef的使用不仅仅是减少了重复的工作量,性能影响可能非常显著,并且还可能产生更易读和更易于维护的编译文件。

需要注意的是:

1、在整个build文件里,<macrodef>是和<target>平级的,上例中定义的<dealWithTestCases>若不将其放在<target>里面,执行Ant时,脚本会直接执行这部分的宏代码,而不会去执行<target>中定义的‘depands=”base”‘依赖关系。

2、<macrodef>可以调用其他的<macrodef>,但不可以调用<target>;<target>可用调用<macrodef>,也可用调用其他<target>。

 3、所有任务的特性通过@{}展开而不是${},它们可以随宏的每一次调用而改变,且只在宏定义程序块内部可用。


作者:jason0539

微博:http://weibo.com/2553717707

博客:http://blog.csdn.net/jason0539(转载请说明出处)

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/121331.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)
blank

相关推荐

  • Java中super()的使用[通俗易懂]

    Java中super()的使用[通俗易懂]目录1.super()的使用实例一一一子类重写父类的方法2.super()的使用实例一一一子类重写父类的变量3.super()的使用实例一一一在子类的构造方法中4.关于构造方法中super()第一种情况:编译不通过第二种情况:编译不通过第三种情况:成功编译通过1.super()的使用实例一一一子类重写父类的方法publicclassA{…

  • Pytest(17)运行未提交的git(pytest-picked)

    Pytest(17)运行未提交的git(pytest-picked)前言我们每天写完自动化用例后都会提交到git仓库,随着用例的增多,为了保证仓库代码的干净,当有用例新增的时候,我们希望只运行新增的未提交git仓库的用例。pytest-picked插件可以

  • activity 工作流程引擎-如何画流程图

    activity 工作流程引擎-如何画流程图前言:activity工作流引擎是当前最流行的工作流,最近公司一直在用这个感觉还是很好用的,学习过程中也有不少的坑所以简单记录一下相关知识的学习过程吧如何画流程图,这里使用浏览器端的一个工具和eclipse里面操作都差不多吧1.流程图里面的节点,如开始,子流程等都是通过拖拽的方式加载的2.一个节点通过点击即可选择下一个节点事件3.如果一个节点出现分支,或者判断的情况可以在流程线上设置…

  • nextSibling 和nextElementSibling的区别[通俗易懂]

    nextSibling 和nextElementSibling的区别[通俗易懂]使用nextSibling属性返回指定节点之后的下一个兄弟节点,(即:相同节点树层中的下一个节点)。nextSibling属性与nextElementSibling属性的差别: nextSibling属性返回元素节点之后的兄弟节点(包括文本节点、注释节点即回车、换行、空格、文本等等); nextElementSibling属性只返回元素节点之后的兄弟元素节点(不包括文本节点、注释节点);注意:空…

  • linux查看防火墙,关闭防火墙,启动防火墙,防火墙定义,对端口用处的理解

    linux查看防火墙,关闭防火墙,启动防火墙,防火墙定义,对端口用处的理解

  • LaTeX数学公式编辑(1)——行内公式&行间公式「建议收藏」

    LaTeX数学公式编辑(1)——行内公式&行间公式「建议收藏」1.行内公式2.行间公式2.1单行编号2.2单行不编号2.3多行编号2.4多行不编号3.说明4.参考文献对数学公式的排版,可以说是LaTeX中最精彩的部分.首先说需要注意的问题.数学公式中有时候会出现文字(中文或英文),需要将文字用命令\text{…}包起来.如果将文字不加处理,直接写到公式里面会出现如下问题:如果…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号