About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • Jul

    30

    StarlingSWF 停止嵌套的 MC

    • 0 Comments
    • Flash Platform
    private function stopMC(mc:SwfMovieClip):void
    {
        mc.stop();
        //记得将播放头设为0,否则它会产生一些意想不到的效果
        //因为默认它的播放头在 -1 位置,并不是在 0 的位置
        mc.currentFrame = 0;

        for(var i:uint = 0; i < mc.numChildren; i++)
        {
            var child:SwfMovieClip = mc.getChildAt(i) as SwfMovieClip;

            if(child)
            {
                stopMC(child);
            }
        }
    }

    Jul

    24

    让 JS 安全的运行在 AS 里

    • 1 Comments
    • Flash Platform

    什么时候都要记得真机调试,否则会死的很惨。先上一段代码:

    package
    {
        import flash.display.Sprite;
        import flash.events.LocationChangeEvent;
        import flash.media.StageWebView;
        //一个 AIR for iOS 的主类
        public class MainTest extends Sprite
        {
            private const view:StageWebView = new StageWebView(true);
            
            public function MainTest()
            {
                super();
                test();
            }

            private function test():void
            {
                view.addEventListener(LocationChangeEvent.LOCATION_CHANGING, locationChaningHandler);

                var xml1:XML = 
                    <script type="text/javascript">
                        var name = prompt("写点什么?","")//当运行的时候我们点击取消   
                        if(name)
                            alert("1:" + name);
                        else
                            alert("2:" + name);
                    </script>;

                view.loadString(xml1.toXMLString());
            }

            private function locationChaningHandler(e:LocationChangeEvent):void
            {
                //我们并不是为了跳转网页,所以这里中止跳转
                e.preventDefault();
            }
        }
    }

    在桌面 AIR 环境中测试,点击取消,输出"2:null",看起来一切良好。可是当连接上手机后,在真机测试环境中测试发现同样的操作结果输出了“1:null”。这和 JS 的自动转型规则完全不一样了,也就是这种 JS 代码运行在 AS 里面它显的那么的不安全。

    将上面的 XML 改为如下这个样子,让 JS 代码运行在一个函数里:

    var xml1:XML = 
        <script type="text/javascript">
            function run()
            &#x7B;
            var name = prompt("写点什么?","");                            
            if(name)
                alert("1:" + name);
            else
                alert("2:" + name);
            &#x7D;
            run();
        </script>;

    现在无论是在桌面上测试,还是在真机环境下,它们都保持输出一致了,都是“2:null”。其中 &#x7B; 与 &#x7D; 两个字符是在 E4X 里 XML 代表的左右大括号转字义符的实体字符。

    也可以将 JS 代码完全剥离 AS,使用一个纯文本文件,然后使用 Embed 标签嵌入。但这个方法对于纯 Flash IDE 开发人员并不适用,因为 Embed 标签需要 FLEX SDK 支持。

    JS 文件(因为是在纯文本文件中,所以左右大括号就不需要转义了;而且仍然要在函数中运行,否则它依然是不安全的,会和桌面测试环境不一致):

    <script type="text/javascript">
        function run()
        {
            var name = prompt("写点什么?","");                            
            if(name)
                alert("1:" + name);
            else
                alert("2:" + name);
        }
        run();
    </script>;

    然后 AS 代码也稍作修改:

    //这里必须写上 mimeType="application/octet-stream"
    [Embed(source="/assets/js/run.js", mimeType="application/octet-stream")]
    static private const JS:Class;

    static public const js:String = new JS();

    private var view:StageWebView = new StageWebView(true);

    private function test():void
    {
        view.addEventListener(LocationChangeEvent.LOCATION_CHANGING, locationChaningHandler);
        view.loadString(js);
    }

    备注:使用静态嵌入的 JS 文件会有两个缺点:1、不能动态的生成 JS 代码了。2、不能使用 AS 的特性了,比如 XML 的绑定语法之类的都不能用了。

    Jul

    24

    在 E4X 语法中,XML 的转义字符有些特别。当这些字符用于属性、属生值、节点、节点值时需要用到转义的情况。其中左右大括号最为特别,因为在 E4X 中语法里,“绑定”语法使用的符号是左右大括号。

     

    Jul

    22

    error while loading initial content

    • 0 Comments
    • Flash Platform

    一般报这样的错误是因为 SWF 内部版本号与 AIR SDK 版本不相符产生的,或 SWF 产生错误运行中止(内部版本号大于 AIR SDK 版本),编译器参数中修改 -swf-version 值,或下载对应的 AIR SDK 版本。

    进程已终止,没有建立到调试器的连接。 
    error while loading initial content

    关于内部版本号:

    Jul

    22

    又一个 Bug,使用类的静态成员引用麦克风对象时无法侦听事件(已经在 AIR SDK 17 与 18 上测试过):

    static private const microphone:Microphone = Microphone.getMicrophone();

    那么在后续后代码中添加侦听器会无法侦听到事件:

    static public function someFunction(): void 
    {
        microphone.setSilenceLevel(04000)//4秒后停止
        microphone.gain = 100;
        microphone.rate = 44;

        //activateHandler与onSampleData事件侦听器都将不会执行
        microphone.addEventListener(ActivityEvent.ACTIVITY, activateHandler);
        microphone.addEventListener(SampleDataEvent.SAMPLE_DATA, onSampleData);
    }

    如果去掉这两个 static 修饰词,将上面的麦风引用改为实例对象是可以侦听到事件的。奇葩!

    Jul

    22

    在 AIR 的 -app.xml 文件中,通过 iPhone - InfoAdditions 节点可以配置与后台运行相关的功能(与后台相关的功能一般指音频、位置更新、网络、选择禁止后台执行应用程序),具体备配方法官方帮助文档有说明:

    http://help.adobe.com/zh_CN/air/build/WSfffb011ac560372f7e64a7f12cd2dd1867-8000.html

    但是需要注意的是,中文帮助文档是与英文帮助文档并不一致(至少从 AIR SDK 3.9 版本开始,到现在的 AIR SDK 18,这两个中英文帮助页面并没有一致):

    http://help.adobe.com/en_US/air/build/WSfffb011ac560372f7e64a7f12cd2dd1867-8000.html

    在中文帮助文档中与后台相关任务中文备注中写的是:对于后台运行的应用程序,不能使用 renderMode=”direct”

    而英文帮助文档里的英文备注部份明显详细的多,:

    NoteWith swf-version 21 and its earlier versions, AIR does not support background execution on iOS and Android when render mode direct is set. Due to this restriction, Stage3D based apps cannot execute background tasks like audio playback, location updates, network upload or download, etc. iOS does not allow OpenGLES or rendering of calls in the background. Applications which attempt to make OpenGL calls in the background are terminated by iOS. Android does not restrict applications from either making OpenGLES calls in the background or performing other background tasks like audio playback. With swf-version 22 and later, AIR mobile applications can execute in the background when renderMode direct is set. The AIR iOS runtime results in an ActionScript error (3768 - The Stage3D API may not be used during background execution) if OpenGLES calls are made in the background. However, there are no errors on Android because its native applications are allowed to make OpenGLES calls in the background. For optimal utilization of mobile resource, do not make rendering calls while an application is executing in the background.

    尤其是如果与 Strarling 框架相结合开发,一般我们都会将 renderMode 设为 direct,在应用被切换到后台的时候,不要修改显示列表中对象,否则就会抛出Error: Error #3768: The Stage3D API may not be used during background execution on this operating system. 所以官方的英文版帮助文档特别说明了不要在后台的时候调用渲染(既便是 CPU 软加速也不推荐在后台更改显示列表中的对象)。

    Jul

    21

    发现 AS3 调用与系统相关的 API 功能时经常会发现 Bug,虽然这些 API 在桌面设备上看起来运行状态良好,但在移动开发时总会与实际情况不符。

    Microphone 类中有一个 muted 属性,可以用来判断用户是否禁用了麦克风访问权限。在网页中与纯 FlashPlayer 里它运行状况良好,但在 iOS 系统里测试时“XXXX 想访问您的麦克风”,无论我选择“不允许”或“好”,它它总是返回 false。然后又是一边 SDK 版本的替换(啊,又是一个“又”),从 SDK 16,换到17、18 测试结果都一样(因为 19 还是 Beta 版,我也懒的去测了)。

    Google 之,发现早在 4.0 版本时就已经有人在 Adobe 官方论坛提交过这个问题,官方没有作任何回复(除了有一个网友回复了一个无关紧要的相册访问的贴子,因为相册是一个应用,它会从一个应用给出提示,而 Microphone 是一个硬件,所以出错后是不会给你提示的;特别是:它的属性在返回时就已经出错了——“把错的当成对的,怎么可能再给出一个错的提示?”)。

    曲线救国的办法:在 setSilenceLevel() 方法中将 silenceLevel 值设为 0,让麦克风对象的 ActivityEvent.ACTIVITY 事件立即执行。建立一个实例变量并设为 false,在 activity 事件侦听器函数中把这个变量设为 true,加一个类似 setTimeout() 函数在200 或 500 毫秒后检测这个变量是否为 true,就可以判断出 activity 事件是否执行过。如果执行过表示有麦克风的访问权限,如果没有执行过,就表过没有权限,给出一个用户提示“设置——隐私——麦克风——XX应用”打开权限。

    Jul

    20

    在移动设备应用开发过程中,性能优化是非常重要的。硬件设备和操作系统在这个时代的更新速度非常,有时候我们既想兼容旧的设备,又想兼容新设备,所以对于一些复杂的大量数据处理时,往往会对旧设备和新设备采用不同的算法。特别是新设备由于拥有较高的性能,所以算法优化的地步也非常大。

    AS3 在 Capabilities 里提供了 supports64BitProcesses 这个 API,用于检测指定系统是否支持运行 64 位的进程。这个 API  在我的 Win 7 64位版桌面应用开发过程中发现它非常好用,但在 iOS 系统检测结果是 64 位的硬件 + 64 位的系统,它返回都是 false(无论我使用 iPhone6 或 iPad Air, 再加上 8.3 和 8.4的最近版本的 iOS 系统,使用了最新的 AIR SDK 16 和 17 测试结果,它都给我返回 false,这应该算是个移动设备上的 Bug 么?)。

    Google 了一下之后,发现很早以前就有人在 Adobe 官方论坛反映过这个问题,但官方没有任何回复。所以暂时不能通过 AS3 来直接判断当前的 iOS 设备是否为 64 位。又要曲线救国了~~(相对来说比较可以接受的解决方法)。

    通过观查《iOS 设备类型》规律,可以找出它设备的硬件版本号(不是操作系统版本号),便有了将优化过的 64 位算法应用到硬件版本号最低限定的那个版本(我想不管屏幕变大变小,硬件总是越升级越高吧?就这么愉快的决定了)。

    通过 Capabilities 类的 os 属性,得到 “iPhone OS x.x iPhonex,x”、“iPhone OS x.x iPadx,x”等类似的字符串,不管是 iPhone、iPad、iPod,它在返回的字符串中一开始写的都是 iPhone,但在最后面那个空格之后,会具体显示是 iPhone、iPad、iPod,这个就足够了。 

    static private function is64Bit(): Boolean {
        var os: String = Capabilities.os;
        var arr: Array = os.split(" ");

        os = arr.pop();

        if (os.indexOf("iPhone") > -1) {
            //iPhone 5s 以上的手机
            if (String(os.split("iPhone")[1]) >= "6,1") {
                return true;
            } else {
                return false;
            }
        } else if (os.indexOf("iPad") > -1) {
            //iPad air 以上的平板,包括 mini
            if (String(os.split("iPad")[1]) >= "4,1") {
                return true;
            } else {
                return false;
            }
        } else if (os.indexOf("iPod") > -1) {
            //据称将来的 iPod 会支持 64 位,暂时就不考虑了
            return false;
        } else {
            //未知设备,也许是个新设备,防止意外就使用未经优化过的算法吧
            return false;
        }

        return false;
    }

    Jul

    20

    iOS 设备类型

    • 0 Comments
    • Miscellaneous
    DEVICE TYPE PRODUCT NAME
    iPhone1,1 iPhone
    iPhone1,2 iPhone 3G
    iPhone2,1 iPhone 3GS
    iPhone3,1 iPhone 4 (GSM)
    iPhone3,3 iPhone 4 (CDMA)
    iPhone4,1 iPhone 4S
    iPhone5,1 iPhone 5 (A1428)
    iPhone5,2 iPhone 5 (A1429)
    iPhone5,3 iPhone 5c (A1456/A1532)
    iPhone5,4 iPhone 5c (A1507/A1516/A1529)
    iPhone6,1 iPhone 5s (A1433/A1453)
    iPhone6,2 iPhone 5s (A1457/A1518/A1530)
    iPhone7,1 iPhone 6 Plus
    iPhone7,2 iPhone 6
    iPad1,1 iPad
    iPad2,1 iPad 2 (Wi-Fi)
    iPad2,2 iPad 2 (GSM)
    iPad2,3 iPad 2 (CDMA)
    iPad2,4 iPad 2 (Wi-Fi, revised)
    iPad2,5 iPad mini (Wi-Fi)
    iPad2,6 iPad mini (A1454)
    iPad2,7 iPad mini (A1455)
    iPad3,1 iPad (3rd gen, Wi-Fi)
    iPad3,2 iPad (3rd gen, Wi-Fi+LTE Verizon)
    iPad3,3 iPad (3rd gen, Wi-Fi+LTE AT&T)
    iPad3,4 iPad (4th gen, Wi-Fi)
    iPad3,5 iPad (4th gen, A1459)
    iPad3,6 iPad (4th gen, A1460)
    iPad4,1 iPad Air (Wi-Fi)
    iPad4,2 iPad Air (Wi-Fi+LTE)
    iPad4,3 iPad Air (Rev)
    iPad4,4 iPad mini 2 (Wi-Fi)
    iPad4,5 iPad mini 2 (Wi-Fi+LTE)
    iPad4,6 iPad mini 2 (Rev)
    iPad4,7 iPad mini 3 (Wi-Fi)
    iPad4,8 iPad mini 3 (A1600)
    iPad4,9 iPad mini 3 (A1601)
    iPad5,3 iPad Air 2 (Wi-Fi)
    iPad5,4 iPad Air 2 (Wi-Fi+LTE)
    iPod1,1 iPod touch
    iPod2,1 iPod touch (2nd gen)
    iPod3,1 iPod touch (3rd gen)
    iPod4,1 iPod touch (4th gen)
    iPod5,1 iPod touch (5th gen)

     相关链接 iOS Device Typeshttp://support.hockeyapp.net/kb/client-integration-ios-mac-os-x/ios-device-types

    Jul

    19

    先上一段代码:

    var novel:XML = <BOOK ISBN="0141182806">
                        <TITLE>Ulysses</TITLE>
                        <AUTHOR>Joyce, James</AUTHOR>
                        <PUBLISHER>Penguin Books Ltd</PUBLISHER>
                    </BOOK>;

    //生成 XMLList 引用部份文档
    var children:XMLList = novel.*;

    // 删除 <PUBLISHER>
    delete novel.PUBLISHER;

    trace(novel)
    // <BOOK ISBN="0141182806">
    // <TITLE>Ulysses</TITLE>
    // <AUTHOR>Joyce, James</AUTHOR>
    // </BOOK>
    trace("================");
    trace(children)
    // <TITLE>Ulysses</TITLE>
    // <AUTHOR>Joyce, James</AUTHOR>
    // <PUBLISHER>Penguin Books Ltd</PUBLISHER>
    // <PUBLISHER> 还是在的,没有受到前面 XML 对于节点删除的操作影响!

    当 XML 中的节点删除时,引用 XML 的 XMLList 并没有受到影响,看起来这部份引用是死的。接下来再看下一段代码:

    var novel:XML = <BOOK ISBN="0141182806">
                        <TITLE>Ulysses</TITLE>
                        <AUTHOR>Joyce, James</AUTHOR>
                        <PUBLISHER>Penguin Books Ltd</PUBLISHER>
                    </BOOK>;

    //生成 XMLList 引用部份文档
    var children:XMLList = novel.*;

    // 这里稍作修改,将原先的删除 <PUBLISHER> 改为值的修改
    novel.PUBLISHER = "HaHa";

    trace(novel)
    // <BOOK ISBN="0141182806">
    // <TITLE>Ulysses</TITLE>
    // <AUTHOR>Joyce, James</AUTHOR>
    // </BOOK>
    trace("================");
    trace(children)
    // <TITLE>Ulysses</TITLE>
    // <AUTHOR>Joyce, James</AUTHOR>
    // <PUBLISHER>Penguin Books Ltd</PUBLISHER>
    // <PUBLISHER>HaHa</PUBLISHER>

    两段代码其实是一模一样的,只是把前一段代码中的 delete 删除一个节点的操作,改为对节点值修改的操作。会发现这部份引用它是活的。

    按照 Colin Moock 《Essential ActionScript 3.0》中第 18 章 “18.9.6. References to Parts of a Document are Not Live”关于 XML 的说法:

    As you change or add new content to an XML object, bear in mind that any updates you make will not be reflected by variables that refer to part of that document.

    这句话仔细的翻译了一下,应该是理解成对于 XML 文档部份的引用是死的,对 XML 文档内容的修改或添加,它是不会反映到部份引用的 XMLList 对象中才对。虽然它里面有一句“Future versions of E4X may support live references to parts of a document.(意思是将来也许可能支持活的)”。

    但实际情况是我在最早的 FLASH CS3 中测试的结果和最新版本的 FLASH CC 版本测试的结果完全一样,也就是它从一开始到现在就是半死不活的……