这两天对Flash游戏如何去接入android平台的SDK做了下研究,做了4399的支付SDK接入的工作,这里与大家分享下。
一、ANE的介绍
(网络描述也是一大堆,这里描述摘自http://blog.csdn.net/myquark/article/details/7904030)
Adobe AIR Native Extension,Adobe AIR的本地扩展,简称ANE。什么叫本地扩展?因为Adobe AIR是跨平台的一个运行时,可以在Windows,Mac,Android,iOS等系统上跑,正是因为其跨平台,所以它本身的功能就有局限性,不可能面面俱到;换句话来说,比如我们想在flash程序中调用一下系统的消息通知功能,但是AIR并没有这个功能,那么怎么办?这就要根据本地平台写段代码,让AIR委托本地平台去执行这段代码,这样就达到了拓展AIR程序的功能。换个角度来看问题,就好像系统有个dll文件,AIR可以去直接调用这个dll文件(这只是一个比方而已,让大家更容易理解,实际上AIR不能直接调用dll文件)。我们可以开发一个Android手机振动程序,然后打包成ANE,这样运行在AIR中的程序就可以调用写好的手机程序了。有了ANE机制,我们就可以开发很多Flash无法完成但是却可以使用的功能。
二、ANE开发步骤
ANE的生成需要两个步骤,一个是生成本地的jar包,一个生成SWC库文件,最后进行编译合成。
本文开发工具为fb 4.7 与eclipse为主
1、创建ane Android项目,生成本地jar包
准备工作
1)在eclipse中创建一个android的项目,假定命名为4399PaySDKANE_JAVA;
2) 将需要依赖的包(4399PaySdk.jar和FlashRuntimeExtensions.jar)添加到项目的libs目录下。
3)在项目属性中-java build path-Libraries下,添加以下
4399PaySdk.jar(4399的支付sdk包,在http://opensj.4399api.net/dev/downloadExchange可以下载到)
FlashRuntimeExtensions.jar(该包在E:\softinstall\ADOBE\Adobe Flash Builder 4.7\sdks\4.6.0\lib\android可找到)
4)在项目属性 - Java Build Path - Order and Export 下,将游戏 SDK 及其依赖的 JAR 包(4399PaySdk.jar)打上勾,确保能够被输出到生成的 JAR 包中;
准备工作有些多哈。接下来正式进入开发。
编码部分:
1、编写 FREContext 的派生类(YJPaymentApiContext.java)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
package
com.sj4399.pay.ane;
import
java.util.HashMap;
import
java.util.Map;
import
com.adobe.fre.FREContext;
import
com.adobe.fre.FREFunction;
public
class
YJPaymentApiContext
extends
FREContext {
@Override
public
void
dispose() {
}
@Override
public
Map<String, FREFunction> getFunctions() {
return
null
;
}
}
|
空的文件先不管。
2、编写 FREExtension 的派生类(如:YJPaymentApiExtension),在 createContext 方法中创建 YJPaymentApiContext的实例,并作为该方法的结果值返回。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package
com.sj4399.pay.ane;
import
com.adobe.fre.FREContext;
import
com.adobe.fre.FREExtension;
public
class
YJPaymentApiExtension
implements
FREExtension {
@Override
public
FREContext createContext(String arg0) {
// TODO Auto-generated method stub
return
new
YJPaymentApiContext();
}
@Override
public
void
dispose() {
// TODO Auto-generated method stub
}
@Override
public
void
initialize() {
// TODO Auto-generated method stub
}
}
|
3、编写一系列 FREFunction 的派生类(如:YJFInit,YJFLogin……等),以实现每一个接口,每个接口方法用一个 FREFunction 派生类实现;
以YJFInit.java为例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
package
com.sj4399.pay.ane;
import
com.adobe.fre.FREContext;
import
com.adobe.fre.FREFunction;
import
com.adobe.fre.FREObject;
import
com.sj4399.pay.YjPaymentApi;
public
class
YJFInit
implements
FREFunction {
private
static
final
String TAG =
"YJFInit"
;
@Override
public
FREObject call(FREContext context, FREObject[] args) {
YJPaymentApiContext yjac = (YJPaymentApiContext)context;
YjPaymentApi.getInstance().init(yjac.getActivity());
return
null
;
}
}
|
我们通过
1
|
context.dispatchStatusEventAsync(callbackString,
""
);
|
进行回调给as3端。编写完其他接口类即可。
4、修改 YJPaymentApiContext的 getFunctions 方法,将实现的每一个 FREFunction 派生类添加到函数集合中,该函数集合作为该方法的结果值返回;此函数集合即承担接口调用职责
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
package
com.sj4399.pay.ane;
import
java.util.HashMap;
import
java.util.Map;
import
com.adobe.fre.FREContext;
import
com.adobe.fre.FREFunction;
public
class
YJPaymentApiContext
extends
FREContext {
@Override
public
void
dispose() {
}
@Override
public
Map<String, FREFunction> getFunctions() {
Map<String, FREFunction> mapFunc =
new
HashMap<String, FREFunction>();
mapFunc.put(
"getUser"
,
new
YJFGetUser());
mapFunc.put(
"charge"
,
new
YJFCharge());
mapFunc.put(
"destoryLogin"
,
new
YJFLogout());
mapFunc.put(
"openLogin"
,
new
YJFLogin());
mapFunc.put(
"init"
,
new
YJFInit());
return
mapFunc;
}
}
|
5、编写 ant 配置文件 build.xml,编译导出 JAR 包
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
|
<?
xml
version
=
"1.0"
encoding
=
"UTF-8"
?>
<
project
name
=
"4399paysdk"
basedir
=
"."
default
=
"exportJar"
>
<!-- 设置全局变量 -->
<
property
name
=
"src.dir"
value
=
"src"
/>
<
property
name
=
"classes.dir"
value
=
"bin/classes"
/>
<
property
name
=
"dist.dir"
value
=
"dist"
/>
<
property
name
=
"jar.file"
value
=
"4399PaySDKANEJava.jar"
/>
<
property
name
=
"classes.encode"
value
=
"UTF-8"
/>
<
property
name
=
"libs.dir"
value
=
"libs"
/>
<
path
id
=
"classpath"
>
<
fileset
dir
=
"${libs.dir}"
>
<
include
name
=
"**/*.jar"
/>
</
fileset
>
<
fileset
dir
=
"E:\softinstall\Java\jdk1.6.0_24\jre\lib"
>
<
include
name
=
"**/*.jar"
/>
</
fileset
>
<
fileset
dir
=
"E:\soft\android\adt-bundle-windows-x86\sdk\platforms\android-8"
>
<
include
name
=
"android.jar"
/>
</
fileset
>
<
fileset
dir
=
"E:\softinstall\ADOBE\Adobe Flash Builder 4.7\sdks\4.6.0\lib\android"
>
<
include
name
=
"FlashRuntimeExtensions.jar"
/>
</
fileset
>
</
path
>
<
target
name
=
"init"
>
<!-- Create the time stamp -->
<
tstamp
/>
</
target
>
<!-- 编译源文件 -->
<
target
name
=
"buildFiles"
depends
=
"init"
>
<
echo
message
=
"start building ....."
/>
<
delete
dir
=
"${classes.dir}"
/>
<
mkdir
dir
=
"${classes.dir}"
/>
<
javac
deprecation
=
"on"
debug
=
"on"
encoding
=
"${classes.encode}"
srcdir
=
"${src.dir}"
destdir
=
"${classes.dir}"
classpathref
=
"classpath"
source
=
"1.6"
target
=
"1.6"
includeAntRuntime
=
"false"
/>
<
copy
todir
=
"${classes.dir}"
>
<!-- copy config files -->
<
fileset
dir
=
"${src.dir}"
includes
=
"**/*.properties,**/*.xml,**/*.bsh,**/*.logic, **/*.hbm"
/>
</
copy
>
</
target
>
<!-- 导出jar文件 -->
<
target
name
=
"exportJar"
depends
=
"buildFiles"
>
<
delete
dir
=
"${dist.dir}"
/>
<!-- Create the distribution directory -->
<
mkdir
dir
=
"${dist.dir}"
/>
<
jar
destfile
=
"${dist.dir}/${jar.file}"
basedir
=
"${classes.dir}"
>
<
zipfileset
excludes
=
"META-INF/*.SF"
src
=
"${libs.dir}/4399PaySdk.jar"
/>
</
jar
>
<
copy
todir
=
"${basedir}/../ane"
file
=
"${dist.dir}/${jar.file}"
/>
</
target
>
</
project
>
|
这样就完成了本地jar包的生成工作了。
2、创建flex库项目,生成swc库
准备工作:
1)创建项目
2)属性设置
编码部分:
这边使用单例模式,创建actionscript代码
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
|
package
com.sj4399.pay.ane
{
import
flash.events.EventDispatcher;
import
flash.events.IEventDispatcher;
import
flash.events.StatusEvent;
import
flash.external.ExtensionContext;
public
class
YjPaymentApi
extends
EventDispatcher
{
public
static
const
EXTENSION_ID:
String
=
"com.sj4399.pay.ane.android"
;
private
var
_context:ExtensionContext;
private
static
var
_instance:YjPaymentApi;
public
static
function
getInstance():YjPaymentApi{
if
(_instance ==
null
){
_instance =
new
YjPaymentApi();
}
return
_instance
as
YjPaymentApi;
}
public
function
YjPaymentApi(target:IEventDispatcher=
null
)
{
_context = ExtensionContext.createExtensionContext(EXTENSION_ID,
null
);
if
(_context ==
null
){
trace
(
"YjPaymentApi(.as) constructor: _context is null,please call 'init()' first!"
);
}
_context.addEventListener(StatusEvent.STATUS,onStatus);
super
(target);
}
/**
* SDK初始化
*/
public
function
init(){
_context.call(
"init"
,
null
);
}
/**
* 登录
*/
public
function
openLogin(){
_context.call(
"openLogin"
,
null
);
}
/**
* 注销
*/
public
function
destoryLogin(){
_context.call(
"destoryLogin"
,
null
);
}
/**
* 充值
* amount 充值金额
* server 分服标识
* mark 拓展标记
*/
public
function
charge(amount:
int
,server:
int
=
0
,mark:
String
=
null
){
_context.call(
"charge"
,amount,server,mark);
}
/**
* 获取用户信息*/
public
function
getUser():
String
{
return
String
(_context.call(
"getUser"
));
}
private
function
onStatus(e:StatusEvent):
void
{
//trace("received status event:"+e.toString());
var
eventObject:
Object
= JSON.parse(e.code);
var
evt:PayCallbackEvent =
new
PayCallbackEvent(Constants.EVENT_TYPE_4399PAYSDK_CALLBACK,
eventObject.callbackType, eventObject.code, eventObject.data);
this
.dispatchEvent(evt);
}
}
}
|
2、编写PayCallbackEvent
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
|
package
com.sj4399.pay.ane
{
import
flash.events.Event;
/**
* 支付SDK回调事件
*/
public
class
PayCallbackEvent
extends
Event
{
private
var
_eventType:
String
;
private
var
_callbackType:
String
;
private
var
_code:
int
;
private
var
_data:
Object
;
public
function
PayCallbackEvent(eventType:
String
, callbackType:
String
, code:
int
, data:
Object
, bubbles:
Boolean
=
false
, cancelable:
Boolean
=
false
)
{
this
._eventType = eventType;
this
._callbackType = callbackType;
this
._code = code;
this
._data = data;
super
(eventType, bubbles, cancelable);
}
/**
* 获取回调事件类型,Constants 中定义了回调事件类型常量(CALLBACKTYE_*),游戏应根据此回调事件类型对事件进行不同的处理。
* @return
*
*/
public
function
get
callbackType():
String
{
return
_callbackType;
}
/**
* 获取回调事件状态码,表示SDK返回的执行结果和状态,StatusCode 中定义了回调事件状态码常量。不同回调事件类型的事件有自己对应的状态列表,游戏应根据此状态码进行不同的处理。
* @return
*
*/
public
function
get
code():
int
{
return
_code;
}
/**
* 获取SDK返回的执行结果数据,不同回调事件类型的事件具有不同的数据结构,游戏应根据回调事件类型来获取相应的数据。
* @return
*
*/
public
function
get
data():
Object
{
return
_data;
}}
}
|
3、定义常量
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
package
com.sj4399.pay.ane
{
public
class
Constants
{
public
static
const
EVENT_TYPE_4399PAYSDK_CALLBACK =
"4399_pay_sdk_callback"
;
public
static
const
CB_LOGIN:
String
=
"login"
;
public
static
const
CB_LOGOUT:
String
=
"logout"
;
public
static
const
CB_CHARGE:
String
=
"charge"
;
public
static
const
STATUS_LOGIN_COMPLETE:
int
= -
1
;
//登录完成
public
static
const
STATUS_LOGIN_CANCEL:
int
= -
2
;
//取消登录
public
static
const
STATUS_LOGOUT_COMPLETE:
int
= -
3
;
//取消登录
public
static
const
STATUS_CHARGE_COMPLETE:
int
= -
4
;
//充值完成
public
static
const
STATUS_CHARGE_CANCEL:
int
= -
5
;
//取消充值
}
}
|
编译在bin目录下可以看到swc库文件。
3、生成ANE
拷贝生成的本地jar文件 与swc文件到要创建ANE的目录下
这里我们可以看到有个extension.xml,这个就是用于as3代码里面的的拓展标识,用于as3调用jar包中的函数,里面内容是
1
2
3
4
5
6
7
8
9
10
11
12
13
|
<
extension
xmlns
=
"http://ns.adobe.com/air/extension/2.5"
>
<
id
>com.sj4399.pay.ane.android</
id
>
<
versionNumber
>1</
versionNumber
>
<
platforms
>
<
platform
name
=
"Android-ARM"
>
<
applicationDeployment
>
<
nativeLibrary
>4399PaySDKANEJava.jar</
nativeLibrary
>
<
initializer
>com.sj4399.pay.ane.YJPaymentApiExtension</
initializer
>
<
finalizer
>com.sj4399.pay.ane.YJPaymentApiExtension</
finalizer
>
</
applicationDeployment
>
</
platform
>
</
platforms
>
</
extension
>
|
signature.p12是air生成的密钥,相信air游戏开发者都清楚这个内容。
以解压的方式打开SWC,解压其中的library.swf到Android-ARM文件夹中。
将jar包和第三方所需要的res资源文件拷贝到Android-ARM中,如图
这里都做好了,接下来就是生成ANE了,我们编写一个批处理文件
1
2
3
4
5
6
7
|
@REM 打包 .ane
SET SWC_FILE=4399PaySDK_ANE_AS.swc
SET ANE_FILE=4399PaySDK.ane
SET JAR_FILE=4399PaySDKANEJava.jar
SET FLEX_ADT_CMD=java -jar
"E:\softinstall\ADOBE\Adobe Flash Builder 4.7\sdks\4.6.0\lib\adt.jar"
%FLEX_ADT_CMD% -package -tsa none -storetype pkcs12 -keystore signature.p12 -storepass 123456 -target ane %ANE_FILE% extension.xml -swc %SWC_FILE% -platform Android-ARM -C Android-ARM .
pause
|
好了,这样就可以生成我们的所需要的ANE了.至于如何调用相信大家都知道,这里就不多说了。
本文转自xuzw13 51CTO博客,原文链接:http://blog.51cto.com/xuzhiwei/1373830,如需转载请自行联系原作者