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)


相关推荐

  • 零基础学Java(4)字符串

    零基础学Java(4)字符串字符串从概念上讲,Java字符串就是Unicode字符序列。例如,字符串"Java\u2122"由5个Unicode字符J、a、v、a和™组成。Java没有内置的字符串类型,而是

  • Activiti工作流的详细介绍[通俗易懂]

    Activiti工作流的详细介绍[通俗易懂]一、了解工作流1、工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现。2、工作流管理系统(WorkflowManagementSystem,WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流逻辑进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的

  • 哪些线程是安全的_redis是线程安全的吗

    哪些线程是安全的_redis是线程安全的吗Java中平时用的最多的map就是hashmap但是它却是线程不安全的。那除了hashmap还有哪些常见的线程安全的map?1.hashtableMap<String,Object>hashtable=newHashtable<String,Object>();这是所有人最先想到的,那为什么她是线程安全的?那就看看她的源码,我们可以看出我们常用的put,get,…

  • setContentView源码学习

    setContentView源码学习参考博客:https://blog.csdn.net/qq_17250009/article/details/52242895https://www.jianshu.com/p/40a9c93b5a8dhttps://www.jianshu.com/p/e42b638944ae特别说明,我用的API版本是25,这句话后面会用到,特别注意!!!今天突然有个想法:不同的布局文件,相…

  • 物联网操作系统的体系构架(物联网系统怎么开发)

    1.       物联网的主要特点                       i.             连接所谓连接,指的是各种各样的终端设备,都能够通过某种网络技术,连接到一个统一的网络上。任何终端之间都可以相互访问。下一代的基础通信网络,包括未来的5G,通信网络架构重构等,为物联网提供泛连接网络是核心目标。目前也已经有很多厂商推出解决方案,比如Google的thread/wave,华

  • ps去除水印的六种方法_PS去水印方法

    ps去除水印的六种方法_PS去水印方法方法一:使用选框工具勾选水印部分:按住Shift+f5选择内容识别:然后ctrl+d取消选择,水印就去掉了PS:其实这个方法有个快捷办法,直接使用选框工具选中之后,按Delete就可以弹出

发表回复

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

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