Flash 와 App간 통신 방법 3가지를 소개했었는데, AS3로 넘어오면서 watch명령이 없어져서 기존에 사용하던 fscommand/setVariable 방법을 사용할수 없어졌습니다. watch 명령이 아주 비효율적이라 아예 없앴다고 합니다. LocalConnection 방법은 편법성으로 사용자들이 알아낸 방법이므로, ExternalInterface로 Flash와 APP간 통신을 구현했습니다.
1. Application에서 Flash 함수 호출
Actionscript3 소스:
ExternalInterface.addCallback("callFromApp", function(a, b) { return "ok:"+a+","+b; });
ExternalInterface.addCallback("callFromApp", function(a, b) { return "ok:"+a+","+b; });
C++ 소스:
string invXml = ExternalInterface::MakeInvokeXml("callFromApp", arg1, arg2);
string ret = ExternalInterface::ParseResultXml(m_cFlash.CallFunction(invXml.c_str()).GetBuffer(0));
string invXml = ExternalInterface::MakeInvokeXml("callFromApp", arg1, arg2);
string ret = ExternalInterface::ParseResultXml(m_cFlash.CallFunction(invXml.c_str()).GetBuffer(0));
2. Flash에서 Application 호출
Actionscript3 소스:
ExternalInterface.call("testfunc", "hello", 1, true, 1==2, 1.1);
ExternalInterface.call("testfunc", "hello", 1, true, 1==2, 1.1);
C++ 소스:
void CFlashTestApp::OnFlashCallShockwaveflash1(LPCTSTR request)
{
string cmd;
vector<string> args;
if (ExternalInterface::ParseInvokeXml(request, cmd, args)) {
// 함수콜 처리하기~
}
}
void CFlashTestApp::OnFlashCallShockwaveflash1(LPCTSTR request)
{
string cmd;
vector<string> args;
if (ExternalInterface::ParseInvokeXml(request, cmd, args)) {
// 함수콜 처리하기~
}
}
--
Flash와 APP간 통신은 모두 XML을 통해서 이루어집니다.
1. 어플에서 XML을 만들고 파싱해야합니다.
2. 외부 XML 파서를 쓸수 있지만, 사용하는 XML이 복잡하지 않아서 자체 XML 파서를 만들었습니다.
3. Flash에서는 type이 있지만, C++에서는 모두 string으로 받도록 했습니다. C++에서 보낼때도 모두String인자로 보냅니다. 어차피 XML이 문자열로 되어 있으므로, string으로 처리해도 퍼포먼스에 크게 영향이 없을것으로생각되고, Variant를 C++에서 구현하는것은 복잡하고 짜증나는 작업이죠.
4. ActionScript에서 전달한 인자 중 복잡한 자료구조는 파싱하지 못하고, String, Number,Boolean등과 1차 Array만 파싱하도록 했습니다. C++에서는 인자 받은걸 순서대로 vector에 넣어서 처리를단순화했습니다. Array안에 Array등을 처리하려면 C++에서도 복잡한 자료구조가 필요하고, 그러면 함수처리하는 부분도복잡해질듯해서 단순화했습니다.
5. STL string을 이용해서 파싱했습니다.
XML 파싱 함수들 입니다.
string peek_element(const string &xml);
xml에 포함된 첫 element를 가져옵니다. peek = 엿보기?
bool parse_element(const string &name, string &xml, string &attrs, string &inner);
xml에 포함된 첫 element를 파싱해서 attribute부분과 innerXml부분으로 나누어줍니다. xml에서는 파싱한 부분을 제거합니다.
name = a
xml = <a attr="haha">aab</a><b>zzz</b>
이런식으로 호출되면...
attrs = attr="haha"
inner = aab
xml = <b>zzz</b>
이런식으로 값이 바뀝니다.
bool parse_attributes(const string &attrs, StringMap &attrMap);
<element attr1="val1" attr2="val2">
위에 같은 xml attributes을 파싱해서 attrMap에 insert합니다. "attr1"→"val1", "attr1"→"val2"
string xml_encode(const string &x); // <, &, > → <, &, >
string xml_decode(const string &x); // <, &, > → <, &, >
Flash -> Application XML 예제
ExternalInterface.call("testfunc", "hello", 1, true, 1==2, 1.1);
<invoke name="testfunc" returntype="xml">
<arguments>
<string>hello</string>
<number>1</number>
<true/>
<false/>
<number>1.1</number>
</arguments>
</invoke>
Flash -> Application XML 파싱 소스:
// external interface 파싱
bool parse_arg(string &xml, string &val)
{
string attrs, i;
if (parse_element("string", xml, attrs, i)) {
val = i;
} else if (parse_element("number", xml, attrs, i)) {
val = i;
} else if (parse_element("true", xml, attrs, i)) {
val = "true";
} else if (parse_element("false", xml, attrs, i)) {
val = "false";
} else if (parse_element("boolean", xml, attrs, i)) {
val = i;
} else {
return false;
}
return true;
}
void parse_args(string &xml, vector<string> &args)
{
string val;
while (1) {
if (parse_arg(xml, val)) {
args.push_back(val);
} else {
break;
}
}
}
bool ParseInvokeXml(const string &_xml, string &cmd, vector<string> &args)
{
string xml=_xml;
string attrs;
string innerXml;
parse_element("invoke", xml, attrs, innerXml);
StringMap attrMap;
parse_attributes(attrs, attrMap);
StringMap::const_iterator f = attrMap.find("name");
if (f != attrMap.end()) {
cmd = f->second;
string elm = peek_element(innerXml);
string p, i;
if (parse_element("arguments", innerXml, attrs, i)) {
innerXml = i;
if (parse_element("array", innerXml, attrs, i)) {
innerXml = i;
while (parse_element("property", innerXml, attrs, i)) {
parse_args(i, args);
}
} else {
parse_args(innerXml, args);
}
}
}
return true;
}
bool parse_arg(string &xml, string &val)
{
string attrs, i;
if (parse_element("string", xml, attrs, i)) {
val = i;
} else if (parse_element("number", xml, attrs, i)) {
val = i;
} else if (parse_element("true", xml, attrs, i)) {
val = "true";
} else if (parse_element("false", xml, attrs, i)) {
val = "false";
} else if (parse_element("boolean", xml, attrs, i)) {
val = i;
} else {
return false;
}
return true;
}
void parse_args(string &xml, vector<string> &args)
{
string val;
while (1) {
if (parse_arg(xml, val)) {
args.push_back(val);
} else {
break;
}
}
}
bool ParseInvokeXml(const string &_xml, string &cmd, vector<string> &args)
{
string xml=_xml;
string attrs;
string innerXml;
parse_element("invoke", xml, attrs, innerXml);
StringMap attrMap;
parse_attributes(attrs, attrMap);
StringMap::const_iterator f = attrMap.find("name");
if (f != attrMap.end()) {
cmd = f->second;
string elm = peek_element(innerXml);
string p, i;
if (parse_element("arguments", innerXml, attrs, i)) {
innerXml = i;
if (parse_element("array", innerXml, attrs, i)) {
innerXml = i;
while (parse_element("property", innerXml, attrs, i)) {
parse_args(i, args);
}
} else {
parse_args(innerXml, args);
}
}
}
return true;
}
[출처] FlashExternalInterface.cpp (원숭이피바다) |작성자 믹스
'etc > old' 카테고리의 다른 글
문자열 형변환 예시 (0) | 2008.05.27 |
---|---|
携帯電話は必要悪(ひつようあく)だ (0) | 2008.05.27 |
Blaze DS 설치 (0) | 2008.05.26 |
暇な時間の使用(しよう) (0) | 2008.05.23 |
철콘 근크리트 (鐵コン筋クリ-ト: Tekkon Kinkreet, 2006) (0) | 2008.05.22 |