About

<#TEMPLATE_INCLUDE_NINEPAGE_ABOUTME#>
  • 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

    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 版本测试的结果完全一样,也就是它从一开始到现在就是半死不活的……

    Jul

    16

    有时候经常想要调用一个简单的对话框,可能是提示,或输入确认等,但并不想花很多时间去为各种分辨率进行设计。这时候能想到的最便捷的方法就是使用原生弹出对话框。

    但 AS3 并没有提供这些原生的便利,不能直接调用原生的对话框功能,需要通过 ANE 才能实现。但客户端的 JS 环境提供了很多的便利,因为 AIR 在移动设备上使用 StageWebView 类时调用的直接就是系统浏览器控件。所以实际上不需要通过 ANE ,只需要通过 JS 就能间接的调用原生的弹出对话框

    代码 + 截图,然后再对效果加以改进。以下以 iOS 8 环境中的截图为样例(已经测试过在 iOS 7 和 8 上都完全正常,效果稍有不同后面说明,安卓机上没有去测试,反正代码都一样,有需要的可以自己去测一下。

    备注:如何通过 AS 运行 JS 并读取 JS的返回值参考《读取 iOS 屏幕物理点数完整样例代码》贴子有完整样例代码。

    JS 字符串代码:

    var str:String = (<![CDATA[
        <script type="text/javascript">
        alert("Hello,你好");
        confirm("Hello,你好");
        var name=prompt("Hello,你好,叫什么名字?","匿名");//将输入的内容赋给变量 name ,
        //这里需要注意的是,prompt有两个参数,前面是提示的话,后面是当对话框出来后,在对话框里的默认值
        </script>
    ]]>);

    在 iOS 设备上运行看效果(点击图片可以看大图):

      

    恩,完全可以使用,但发现它的标题是 “http://adobe.1437011307.apollo.air”,效果太差了,Google 了一下之后没有发现可以修改的方法,囧 - - 。但是还是找到了一个去掉标题的方法,继续往下,把 JS 代码修改成下面这样子:

    var str:String = (<![CDATA[
        <script type="text/javascript">
            var iframe = document.createElement("IFRAME");
            iframe.setAttribute("src""data:text/plain;");
            document.documentElement.appendChild(iframe);
            window.frames[0].window.alert("Hello,你好");
            window.frames[0].window.confirm('Hello,你好');
            window.frames[0].window.prompt('Hello,你好,叫什么名字?',"匿名");
            iframe.parentNode.removeChild(iframe);
        </script>
    ]]>);

    再运行看看效果:

      

    标题消失了,仔细一点看,这个没有标题的弹出对话框中文字,相对于前面带有标题的对话框而言文字变粗了一点(在 iOS 7 上它并不会变粗,在 iOS 8 上面才变粗一点)。效果到了勉强可以接受的地步。

    Jun

    28

    升级 iTunes 几天后,发现 FlashBuilder 4.7 在真机调试时 AIR SDK 找不到设备,显示“Flash Bulider找不到连接的设备”。像上次一样 CMD 命令行中输入(啊~,我为什么要说像上次一样):

    <Flash Builder 4.7 Program Files>\eclipse\plugins\com.adobe.flash.compiler_4.7.0.348297\AIRSDK\lib\aot\bin\iOSBin\idb.exe -devices

    提示:

    iTunes MobileDevice library not found.Please check your iTunes installation.

    Google 之,找到“iTunes 12.1.2(Windows 版)(64 位,适用于较早的显卡)”,下载,安装,搞定。

    备注:具体原因不清楚,但可以肯定不是因为显卡原因,因为刚一开始自动升级 iTunes 12.1.2 版本后的几天是可以真机调试的,过了几天才不能真机调试。

    Jun

    26

    继续《Adobe AIR 读取屏幕物理点数(非物理尺寸、非像素尺寸)的方法》,如果不使用 StageWebViewBridge-master,这里提供一个通过 StageWebView 获取 iOS 屏幕物理点数的样例代码(如果是安卓系统,可以直接用那篇文章中引用的官方推荐值 DPI 值 160)。

    JS 部份主要代码:

    package
    {
        public class ScreenJS
        {
            public function ScreenJS()
            {
                throw Error("无法实例化的类")
            }

            //这是一个奇怪的字符串写法
            //可以参考这个贴子:http://blog.zinewow.com/post/270.html
            //这样写的目的只是为了方便字符串在AS中换行
            static public const xmlString:String =

            (<![CDATA[
                <script type="text/javascript">

                    function getInfo() 
                    {
                        var u = navigator.userAgent;


                        if(u.indexOf('iPhone') > -1 || u.indexOf('iPad') > -1)
                        {
                            window.location.href = "http://127.0.0.1/?" + window.screen.height + "x" + window.screen.width;
                        }
                    }     

                    getInfo() ;

                </script>
            ]]>);
        }
    }

    AS 部份主要代码:

    //某个地方生成了 StageWebView 对象并添加了侦听器,一般就要主函数吧
    var view:StageWebView = new StageWebView();

    view.stage = stage;
    view.addEventListener(LocationChangeEvent.LOCATION_CHANGING, locationChaningHandler);
    view.loadString(ScreenJS.xmlString);


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

          var location:String = e.location;
          var dpi:String= String(location.split("?")[1]);
          trace("dpi:", dpi);
    }

    Jun

    25

    BlackBerry PlayBook SDK for Adobe AIR

    • 0 Comments
    • Flash Platform

    在找资料的时候发现黑莓曾经居然为 ADOBE AIR 移动开发做过独立的组件:

    https://developer.blackberry.com/playbook/air/apis/qnx/ui/listClasses/package-detail.html

    Jun

    24

    将 APP 制作成为横向的应用,在 -app.xml 中设置 aspectRatio 为 landscape,并禁止它的旋转功能 autoOrients 为 false,通过 StageWebView 调用 JS 读取屏幕的宽与高。时此 JS 返回的仍然是垂直时 APP 的屏幕物理点数(关于物理点数,请参考这里),并非是旋转后屏幕的物理点数(与 stage 方向并不一致,不知道这算不算 Bug)。

    以 iPad AIR 为例:

    读取屏幕:alert(window.screen.height + " x " + window.screen.width);

    向的 APP 得到的物理点数并非  768 x 1024,而是1024 x 768(依旧是垂直方向的物理点数)。