为什么要写一个App

    首先解释下写出来的这个App,其实无任何功能,只是用HTML和CSS模仿JD移动端界面写的一个适配移动端的Web界面。本篇主要内容是介绍如何使用PhoneGap把开发出来的mobile web app快速打包成Native App。最近还在学习HTML&CSS以及Javascript,偶然想想学这些有什么用,一方面可以做Web系统的前端开发,另一方面也可以做移动端的Web App。刚好最近了解到PhoneGap,研究了一下它的框架平台,花了两个晚上终于把一个web系统变成了一个移动终端App。如果是做外包项目或者简单应用App,感觉用PhoneGap还是可以,能够使用一套Web代码快速的实现多个平台App。例如IOS、Android、Windows Phone、WebOS等等。

先介绍代码

    要让我们的web代码能够打包成Native App。首先必须要有一个index.html页面,并且需要添加一些额外代码。在header上需要添加一个name为viewport的meta节点。代码如下:



<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />


    viewport用来初始化视窗参数,这些参数包括应用内容在多大的屏幕上显示以及内容的缩放级别等等。initial-scale指定加载的内容按多大的缩放比例显示,上面initial-scale为1表示应用内容按100%显示。maximum-scale、minimum-scale控制缩放的最大最小比例。userscalable属性控制用户是否允许控制scale和zoom,就如使用两个手指缩放内容。

    接下来需要在body结尾之前添加一段js引用代码,代码如下:



<script type="text/javascript" src="cordova.js"></script>



    cordova是PhoneGap的js库,提供了一套接口,用来访问本地设备的硬件操作。例如可以操作摄像机、联系人、GPS等。cordova引入之后还得在body结尾之前添加一段js代码,用来初始化app。代码如下:


<script type="text/javascript">
        app.initialize();
</script>


    app.initialize()是自定义的一个方法。app是一个全局对象,app对象实现如下:



ios模拟器无法购买测试_移动开发



var app = {
    // 应用构造函数
    initialize: function() {
        this.bindEvents();
    },
    // 绑定事件监听
    //
    // 绑定任何事件需要在启动时绑定
    // '之间包括:load', 'deviceready', 'offline', and 'online'.
    bindEvents: function() {
        document.addEventListener('deviceready', this.onDeviceReady, false);
    },
    // deviceready事件
    onDeviceReady: function() {
        app.receivedEvent('deviceready');
    },
    //deviceready绑定的具体事件
    receivedEvent: function(id) {
        changeElementOpacityByScroll($(".jd-search-cover"));
    },
    //改变元素透明度
    changeElementOpacityByScroll:function(ele){
        $(window).bind("scroll", function(event){
            //所有内容的高度
            var scrollTotalHeight = Math.max(document.body.scrollHeight, document.documentElement.scrollHeight)
            //已被滚动的高度
            var winScrollHeight = Math.max(document.body.scrollTop, document.documentElement.scrollTop);
            var ratio = winScrollHeight / scrollTotalHeight;
            var opacity;
            //元素透明度变化,是在滚动条位置占比在0-20%的范围内。
            if(ratio > 0.2){
                opacity = .8;
            }else if(ratio <= 0){
                opacity = 0;
            }else {
                // 20% * 4 = 。8正好是透明度的最大值
                opacity = ratio * 4.0;
            }
            if(opacity){
                $(ele).css("opacity", opacity);
            }
        })
    }
};



ios模拟器无法购买测试_移动开发



     上段代码表示在应用启动时注册deviceready事件,上面代码的核心也是deviceready事件,它是cordova提供的一个事件。这个事件标明cordova的设备API已经加载完成,我们可以使用cordova的API操作设备。然后在deviceready事件中添加加载完成的初始化代码,相当于页面的onload事件。

    最后附上index.html页面的主要代码,如下:



ios模拟器无法购买测试_移动开发



<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <!-- 添加viewportmeta标签元素 -->
    <meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width" />
    <title>专业网上购物平台品质保障! - 京东商城</title>
    <link rel="stylesheet" type="text/css" href="css/base.css">
    <link rel="stylesheet" type="text/css" href="css/index.css">
    <link rel="stylesheet" type="text/css" href="css/themes/default/jquery.mobile-1.4.5.min.css">
</head>
<body>
    <section data-role="page" id="main">
        <section class="jd-section">
            <header class="section-wrapper">
                <div class="header-home-wrapper ">
                    <div class="jd-search-cover"></div>
                    <div class="js-search-icon">
                        <span class="jd-search-icon-logo">
                             <i class="jd-icon"></i>
                        </span>
                    </div>
                    <form class="jd-search-form">
                        <div class="jd-search-form-box">
                            <span class="jd-search-form-icon jd-sprite-icon"></span>
                            <div class="js-search-form-input">
                                <input type="text" placeholder="夏日畅饮,可口可乐满99减50"/>
                            </div>
                        </div>
                    </form>
                    <div class="jd-login-icon">
                        <a href="#"><span>登录</span></a>
                    </div>
                </div>
                <div>
                    <img style="width: 100%;" src="images/adv.jpg">
                </div>
            </header>
            <article class="section-wrapper">
                <div class="ui-grid-c">
                    <div class="ui-block-a">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/chaoshi.png">
                            </div>
                            <div style="text-align: center;">
                                <span>京东超市</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-b">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/jinkou.png">
                            </div>
                            <div style="text-align: center;">
                                <span>全球购</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-c">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/chongzhi.png">
                            </div>
                            <div style="text-align: center;">
                                <span>充值中心</span>
                            </div>
                        </div>
                    </div>

                    <div class="ui-block-d">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/shishang.png">
                            </div>
                            <div style="text-align: center;">
                                <span>服装城</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-a">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/licai.png">
                            </div>
                            <div style="text-align: center;">
                                <span>理财</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-b">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/juan.png">
                            </div>
                            <div style="text-align: center;">
                                <span>领卷</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-c">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/wuliu.png">
                            </div>
                            <div style="text-align: center;">
                                <span>物流查询</span>
                            </div>
                        </div>
                    </div>
                    <div class="ui-block-d">
                        <div class="jd-nav-item">
                            <div>
                                <img src="images/guanzhu.png">
                            </div>
                            <div style="text-align: center;">
                                <span>关注</span>
                            </div>
                        </div>
                    </div>
                </div>
            </article>
            ...省略了其他代码
            <footer class="bottom-bar-panel" data-role="footer" data-position="fixed">
                <ul class="horizontal-ul">
                    <li class="column-5">
                        <a class="nav-bottom-link" href="#main">
                            <img src="images/navigate/main.png">
                        </a>
                    </li>
                    <li class="column-5">
                        <a class="nav-bottom-link" href="#main">
                            <img src="images/navigate/category.png">
                        </a>
                    </li>
                    <li class="column-5">
                        <a class="nav-bottom-link" href="#main">
                            <img src="images/navigate/find.png">
                        </a>
                    </li>
                    <li class="column-5">
                        <a class="nav-bottom-link" href="#main">
                            <img src="images/navigate/shoppingCart.png">
                        </a>
                    </li>
                    <li class="column-5">
                        <a class="nav-bottom-link" href="#main">
                            <img src="images/navigate/myself.png">
                        </a>
                    </li>
                </ul>
            </footer>
        </section>
    </section>
    <script type="text/javascript" src="js/jquery.min.js"></script>
    <script type="text/javascript" src="js/jquery.mobile-1.4.5.min.js"></script>
    <script type="text/javascript" src="cordova.js"></script>
    <script type="text/javascript" src="js/jd.js"></script>
    <script type="text/javascript">
        app.initialize();
    </script>
</body>
</html>



ios模拟器无法购买测试_移动开发



需要准备哪些软件

    前端开发:NodeJs(使用版本v4.4.2)、Git(使用版本2.7.2)、WebStorm(使用版本11.0.3)。

   android环境:Java SDK(使用版本jdk-8u91)、android studio(使用版本143.2821654)。

    框架平台:PhoneGap(使用 版本0.3.3)、PhoneGap Developer App(移动端手机App,用于手机端调试)、Cordova(命令行工具)。

PhoneGap介绍

    首先,PhoneGap是一个平台,它能够让一个开发人员开发出能够运行在不同平台的移动端设备上的App。开发人员只需要熟悉HTML、CSS、Javascript技术。PhoneGap平台可以把开发人员写的HTML、CSS和Javscript文件打包部署到各种移动端App(例如IOS、Android等等)。但使用Web端技术实现的App是没有权限直接访问设备上的文件系统和摄像头等,PhoneGap有一套Bridge机制可以让Javscript运行在WebView上去调用本地代码,从而实现本地操作。也就相当于PhoneGap为我们提供了一套本地操作的接口,这套操作接口的JS库就是Cordova。接口包括操作摄像头、联系人、文件系统、音视频播放、录像、网络访问等。

    如果有些本地功能PhoneGap没有实现怎么办?PhoneGap也支持插件模式,开发人员可以自己实现某些功能,然后通过插件形式附加到PhoneGap项目中。但需要说明的是,插件都是基于Native开发的,例如Android或者IOS平台。所以要添加插件,开发人员不得不熟悉Native(例如Android或者IOS)开发。

搭建过程

    这里主要介绍PhoneGap的搭建过程。像NodeJs、Git、WebStorm的安装这里我们不再做介绍了。NodeJs为我们提供了命令行工具,我们可通过npm下载各种js库。Git用于代码管理。WebStorm是一个Web开发的IDE工具。

第一步,安装客户端

    首先我得下载一个PhoneGap桌面客户端,PhoneGap官网上为我们提供了IOS和Window系统的下载链接。由于我们在Windows 10系统上开发,所以我需要下载Windows版本的客户端,下载地址链接请点击Windows Installer。安装的过程直接点下一步知道完成即可。打开PhoneGap客户端,可看到主界面如下所示:

ios模拟器无法购买测试_java_05

第二步,安装移动端调试App

    PhoneGap提供了各个平台的调试App,我们可以直接通过这些App来查看和调试我们的程序,而不需要安装各个平台的SDK。下载链接:

    *ITunes

    *Google Play

    *Windows Phone Store

    由于Google在国内被封,所以不怎么好下载。这里我提供云盘上的下载地址,密码为k2cy。

    下载安装后,可看到如下界面:

   

ios模拟器无法购买测试_css_06

第三步,创建PhoneGap项目

    点击PhoneGap客户端左栏的“+”号,然后选择Create new PhoneGap project…。界面如下:

ios模拟器无法购买测试_操作系统_07

创建一个新的项目需要我们填写一些参数,界面如下:

ios模拟器无法购买测试_css_08

    Local Path选择我们项目创建的路径,Name为项目名称(例如FirstApp),Id为项目命名空间(例如hi.mobile.firstapp,和java的包名有点相似)。参数填写完之后,点击“Create project”创建项目。   

    项目创建后,我们到代码目录去查看一下生成的代码,可看到有这几个文件夹:

ios模拟器无法购买测试_ios模拟器无法购买测试_09

    对于这几个文件夹,目前我们只用关系www,通过文件夹名称就可看出和web相关。打开文件夹,查看到的目录结构如下:

ios模拟器无法购买测试_移动开发_10

    www下的目录结构和我们经常创建的web项目目录很相似。没错,这个目录正是用于存放我们自己写的web项目,所以我们可以把原有的这些文件全部删掉,然后直接把我们写的web代码拷贝到这个目录下。如果想让代码能够跑起来,我们还得修改index.html界面内容,具体怎么修改请查看前面“先代码介绍”部分。

第四步,使用Cordova调试项目

    项目搭建完之后,我们需要调试代码。调试代码依赖于cordova命令行工具,需要使用npm下载cordova。打开node.js命令行工具,执行以下命令:



npm install -g cordova



    可能需要等待一段时间,请耐心。cordova安装完后,我们就可以调试代码。如何调试代码?首先我们需要在PhoneGap客户端主界面启动Web服务,在下面的界面中我们通过点击”>”图标启动服务。

 

ios模拟器无法购买测试_ios模拟器无法购买测试_11

    服务启动后主界面底部能够看到”Server is running on http://192.168.1.*:3000”提示,表示服务已经启动成功。既然是一个http地址,那么也可以直接在浏览器上访问。打开chrome浏览器,输入上面的http地址,项目运行如下:

   

ios模拟器无法购买测试_ios模拟器无法购买测试_12

    运行结果是不是和京东首页很想,但只是一些html和css效果。接下来我们还需要在手机端查看运行情况。这里就得提到之前安装的移动终端调试app程序,打开手机上的PhoneGap app,运行界面如下:

ios模拟器无法购买测试_移动开发_13

     在地址栏中输入PhoneGap PC客户端启动的服务地址,然后点击“Connect”,app会提示“succes”。表示链接服务成功,接下来就可以看到手机上代码运行效果。界面如下:

ios模拟器无法购买测试_ios模拟器无法购买测试_14

     到目前为止,我们能够在pc端和手机端调试我们的项目了。接下来的工作就是敲代码、调试、敲代码、调试,直到开发完成。项目开发完成之后,就得考虑如何把项目打包成app。

第五步,打包项目为Android App

    其实打包的过程比较简单,直接使用cordova执行几条命令即可打包,麻烦的是需要安装android环境。在“需要准备哪些软件”中有说到android环境,包括java sdk和android studio。其实应该是java sdk和anroid sdk,但android sdk下载比较麻烦,我们可以直接安装一个android studio,它本身也包含了android sdk。

    java sdk和android studio的安装都比较简单,基本上都是直接下一步下一步。安装完成之后需要配置环境变量。包括:

     (1)JAVA_HOME:指向java sdk安装目录

   (2)ANDROID_HOME:指向android sdk的安装目录。默认安装目录为X:\Users\PC登录名\AppData\Local\Android\sdk。

   (3)在系统变量PATH中添加两个路径:



X:\Users\PC登录名\AppData\Local\Android\sdk\platform-tools
X:\Users\PC登录名\AppData\Local\Android\sdk\tools



    android环境配置完成后需要在PhoneGap项目中添加android平台。打开NodeJs命令行工具把路径切换到我们PhoneGap项目目录下。然后执行命令:


$ cordova platform add android #ios命令为cordova platform add ios


    上面的命令执行的时间比较长,执行过程中根据打印的日志可以看到下载了很多jar包,其实就是下载android app的依赖环境。命令执行完成后,PhoneGap项目目录下的platform文件夹下多了一个android文件夹,android目录结构如下:

ios模拟器无法购买测试_java_15

    现在PhoneGap项目中android平台已经添加了,接着就可以直接把项目build成一个android版本app。执行如下命令:



$ cordova build android


    上面的命令执行完后,打开platforms\android\build\outputs\apk目录,看到生成一个叫做android-debug.apk,这个就是我们最终build成的android应用安装包。如下图所示:

ios模拟器无法购买测试_移动开发_16

    另外,也可通过下面的命令使用andoroid模拟器调试应用。命令如下:



$ cordova emulate android



    剩下的操作就是把构建成的apk安装包在手机上安装,安装完后就可以像其他app一样正常使用。

附上参考网站

    (1)PhoneGap官网的Get Started:http://phonegap.com/getstarted/

    (2)比较全面的介绍如何搭建PhoneGap项目:https://www.smashingmagazine.com/2014/02/four-ways-to-build-a-mobile-app-part3-phonegap/

    (3)怎么把我们的代码变成PhoneGap能执行的代码:http://docs.phonegap.com/develop/hello-world-explained/

    (4)Android平台环境部署:http://cordova.apache.org/docs/en/latest/guide/platforms/android/index.html

   

    另外,代码我放到了Github上,用来做测试的可去下载:

    https://github.com/heavis/PhoneGap.git