使用ionic+angular+phonegap开发APP入门

有时候朋友问我是做什么的?我说以前是用PHP写后台,最近是用H5写前台APP(俗称的Hybrid App); 
在公司做了几个H5的项目之后,有时候也想抽空研究下H5写一些APP;总觉得写APP的开发更加有底气。尽管我偶尔有空也会研究下android,swift(Objective-C实在是难懂,没兴趣深入研究),也希望H5能开发一些不错的APP; 
国内有包括APPCan等公司慢慢在发力,是很不错的趋势;由于mac上面无法使用APPCAN,所以我就没继续研究了,就看国外是怎么的一个过程;偶尔的机会发现了有人用ionic+angularjs+phonegap,很不错的尝试;于是我也想摸索下;

结论:使用上述的方法开发app,是可行的,至少我再android+IOS上面打包是成功了,体验还可以,开发比较方便,基于一些现成的组件;能在1~2天开发一个简单的demo;效率比较高,不过你需要对angularjs有一定的熟悉和了解;H5也一样;所以我也是慢慢学习慢慢研究;

入门必须: 
(1) 看一遍ionic的文档, http://ionicframework.com/ ; 
Ionic 是一个用HTML, CSS 跟JS 开发的一个用于移动设备的web app 开发框架,采用 Sass与AngularJS 开发。

(2) 看一遍phonegap的文档;目前phonegap又取名为cordova;有些常用的命令总结如下:

项目例子:http://my.oschina.net/nosand/blog/294011 
ionic: 
Create hybrid mobile apps with the web technologies you love. 
Free and open source, Ionic offers a library of mobile-optimized HTML, 
CSS and JS components, gestures, and tools for building highly interactive apps. 
Built with Sass and optimized for AngularJS.

Qunee有一个上海地铁图的例子,有客户希望转成mobile app,考察过android的webview,以及PhoneGap等多种Hybrid App方案后,最后选择使用ionic,准确的说是ionic + PhoneGap + Qunee ionic是一种基于HTML5创建Hybrid应用的前端框架,借助phoneGap + angularJS实现一套跨平台,轻量的移动UI方案,本文将介绍借助ionic实现移动版Qunee上海地图的示例 
背景知识

安装ionic所需软件环境 – java, android sdk等

ionic实际上是集大成者,借助了多种技术,自身是一套UI框架,结合PhoneGap实现跨平台移动APP,需要先安装好依赖的程序,比如nodejs, java, ADT, ant, xcode等,并设置好java_home, 添加android sdk tool到环境变量

mac os x下安装ant

brew update 
brew install ant 
#mac osx 下,打开.bash_profile文件 
cd ~ 
open .bash_profile 
#设置相关的Path,mac os x下增加类似下面的内容 
export JAVA_HOME= /usr/libexec/java_home -1.8

# android 
export PATH=${PATH}:/Users/macbook/WorkSpace/android-sdk-macosx/platform-tools:/Users/macbook/WorkSpace/android-sdk-macosx/tools

安装ionic和cordova

需要首先安装好nodejs,然后通过npm来安装

npm install -g cordova ionic 
更多请参考官方文档+google http://ionicframework.com/getting-started/ 
创建ionic项目q-metro

使用下面的命令创建一个新的项目 
ionic start q-metro 
初始目录结构如下

codingless|使用ionic+angular+phonegap开发APP入门

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">
    <title></title>

    <link href="http://www.webdoes.com/archives/lib/ionic/css/ionic.css" rel="stylesheet">
    <link href="http://www.webdoes.com/archives/css/style.css" rel="stylesheet">

    <!-- IF using Sass (run gulp sass first), then uncomment below and remove the CSS includes above
    <link href="http://www.webdoes.com/archives/css/ionic.app.css" rel="stylesheet">
    -->

    <!-- ionic/angularjs js -->
    <script src="http://www.webdoes.com/archives/lib/ionic/js/ionic.bundle.js"></script>

    <!-- cordova script (this will be a 404 during development) -->
    <script src="http://www.webdoes.com/archives/cordova.js"></script>

    <!-- your app's js -->
    <script src="http://www.webdoes.com/archives/js/app.js"></script>
  </head>
  <body ng-app="app" ng-controller="Metro" animation="slide-left-right-ios7">
    <ion-header-bar class="bar-dark">
      <h1 class="title">{{title}}</h1>
    </ion-header-bar>
    <ion-content scroll="false">
      <div id="canvas" style="width: 100%; height: 100%;"></div>
    </ion-content>
  </body>
  <script src="http://www.webdoes.com/archives/lib/qunee/qunee-min.js"></script>
</html>

index.html结构

首先看index.html,是主页面,里面引入了angularjs, cordova等js支持,此外还有app.js, controllers.js, services.js三个文件,这三个文件构建了app的应用逻辑,app是主程序,包含一些设置和启动脚本,services是数据支持部分,也就是model部分,用于提供数据的增删改查操作,controllers用于控制,包含业务逻辑控制代码

先在桌面环境下测试,Chrome运行正常,然后编译成各种移动平台版本,这里以android版本为例 
ionic start q-metro 
cd q-metro 
ionic platform add android 
ionic build android 
ionic run android 
如果要在虚拟机中测试,可以改用 
ionic emulate android 
ionic支持多种移动平台,如果希望创建ios可以将”android”改成”ios” 下面是android设备上真机运行界面如下:

给大家看看一个简单的demo的效果:

codingless|使用ionic+angular+phonegap开发APP入门

codingless|使用ionic+angular+phonegap开发APP入门

源码如下也很简单,供大家学习:

index.html如下:

<!DOCTYPE html>
<html ng-app="ionicApp">
<head>

  <meta charset="utf-8">
  <meta name="viewport" content="initial-scale=1, maximum-scale=1, user-scalable=no, width=device-width">

  <title>Ionic-AngularJS Kitchen Sink</title>

  <!--<link href="http://code.ionicframework.com/1.0.0-beta.1/css/ionic.min.css" rel="stylesheet">-->
  <!--<script src="http://code.ionicframework.com/1.0.0-beta.1/js/ionic.bundle.min.js"></script>-->
  <link href="http://www.webdoes.com/archives/lib/ionic/css/ionic.beta.min.css" rel="stylesheet">
  <script src="http://www.webdoes.com/archives/lib/ionic/js/ionic.bundle.beta.min.js"></script>

  <script src="http://www.webdoes.com/archives/js/app.js"></script>

  <style>
      .box {height:300px;padding: 10px}
  </style>      
</head>

<body ng-controller="AppCtrl">

  <ion-nav-bar class="nav-title-slide-ios7 bar-positive">
    <ion-nav-back-button class="button-icon ion-arrow-left-c">
    </ion-nav-back-button>
  </ion-nav-bar>

  <ion-nav-view animation="slide-left-right"></ion-nav-view>

    
  <script id="menu.html" type="text/ng-template">
    <ion-side-menus>

      <ion-side-menu side="left">
        <ion-header-bar class="bar-positive">
          <h1 class="title">Side Menu</h1>
        </ion-header-bar>
        <ion-content>
          <ul class="list">
            <a href="http://www.webdoes.com/archives/609.html#/menu/tab/buttons" class="item" menu-toggle="left">问答服务</a>
            <!--<a href="http://www.webdoes.com/archives/609.html#/menu/keyboard" class="item" menu-toggle="left">Keyboard Input Types</a>-->
            <!--<a href="http://www.webdoes.com/archives/609.html#/menu/slidebox" class="item" menu-toggle="left">Slide Box</a>-->
            <a href="http://www.webdoes.com/archives/609.html#/menu/about" class="item" menu-toggle="left">About</a>
          </ul>
        </ion-content>
      </ion-side-menu>

      <ion-side-menu-content>        
        <ion-nav-view name="menuContent"></ion-nav-view>
      </ion-side-menu-content>

    </ion-side-menus>
  </script>    
    
  <script id="tabs.html" type="text/ng-template">
    <ion-nav-bar class="bar-positive">
        <ion-nav-back-button class="button-icon ion-arrow-left-c">
        </ion-nav-back-button>

        <ion-nav-buttons side="left">
          <button class="button button-icon button-clear ion-navicon" ng-click="toggleLeft()"></button>
        </ion-nav-buttons>

        <ion-nav-buttons side="right">
          <button class="button button-icon button-clear ion-compose" ng-click="modal.show()"></button>
        </ion-nav-buttons>
    </ion-nav-bar>
        
    <ion-tabs class="tabs-icon-top tabs-positive">

      <ion-tab title="问答" icon="ion-pricetag" href="http://www.webdoes.com/archives/609.html#/menu/tab/buttons">
        <ion-nav-view name="buttons-tab"></ion-nav-view>
      </ion-tab>

      <ion-tab title="日记" icon="ion-clipboard" href="http://www.webdoes.com/archives/609.html#/menu/tab/list">
        <ion-nav-view name="list-tab"></ion-nav-view>
      </ion-tab>

      <ion-tab title="健康汇" icon="ion-settings" href="http://www.webdoes.com/archives/609.html#/menu/tab/form">
        <ion-nav-view name="form-tab"></ion-nav-view>
      </ion-tab>

    </ion-tabs>
  </script>

  <script id="buttons.html" type="text/ng-template">
    <ion-view title="大咖问答">
      <ion-content class="padding">
        <div class="head" style="background-image: url(img/headImg.jpg);background-size: cover;position:relative;height: 120px;">
        </div>
        <div class="item item-divider">
          问答集锦
        </div>

        <ion-list>
          <ion-item ng-repeat="testItem in testItems" item="testItem" href="http://www.webdoes.com/archives/609.html#/menu/tab/testItem" data-id="{{testItem.id}}">
            问题标题: {{ testItem.title }}
          </ion-item>
          </ion-list>
      </ion-content>
    </ion-view>
  </script>

  <script id="item.html" type="text/ng-template">
    <ion-view title="Item">
      <ion-content class="padding">
        <p>内容暂时没提供</p>
      </ion-content>
    </ion-view>
  </script>

  <script id="testItem.html" type="text/ng-template">
    <ion-view title="testItem">
      <ion-content class="padding">
        <p>内容暂时没提供</p>
      </ion-content>
    </ion-view>
  </script>

  <script id="list.html" type="text/ng-template">
    <ion-view title="日记列表">
      <ion-content>
        <ion-list show-delete="data.showDelete" on-delete="onItemDelete(item)" option-buttons="itemButtons">

          <div class="list">
            <!--<div class="item item-divider">-->
            <ion-item ng-repeat="item in items" item="item" href="http://www.webdoes.com/archives/609.html#/menu/tab/item">
              Item {{ item.id }}
            </ion-item>
          </div>

        </ion-list>
      </ion-content>
    </ion-view>
  </script>

  <script id="form.html" type="text/ng-template">
    <ion-view title="健康专栏">
      <ion-content class="padding">
        开发中,尽请期待...
        <br>

      </ion-content>
    </ion-view>
  </script>
    
  <script id="slidebox.html" type="text/ng-template">
    <ion-view>
      <ion-header-bar class="bar-positive">
          <button class="button button-icon button-clear ion-navicon" ng-click="toggleLeft()"></button>
          <h1 class="title">Slide Box</h1>
      </ion-header-bar>
      
      <ion-content>
        <ion-slide-box>
          <ion-slide>
            <div class="box">
                <h2>Box #1</h2>
                <p>Content goes here</p>
            </div>
          </ion-slide>
          <ion-slide>
            <div class="box">
                <h2>Box #2</h2>
                <p>Content goes here</p>
            </div>
          </ion-slide>
          <ion-slide>
            <div class="box">
                <h2>Box #3</h2>
                <p>Content goes here</p>
            </div>
          </ion-slide>
        </ion-slide-box>
       </ion-content>    
    </ion-view>
  </script>   

  <script id="keyboard.html" type="text/ng-template">
    <ion-view>
      <ion-header-bar class="bar-positive">
        <button class="button button-icon button-clear ion-navicon" ng-click="toggleLeft()"></button>
        <h1 class="title">Keyboard Input</h1>
      </ion-header-bar>
      
      <ion-content class="padding">
        <div class="list">        
          <label class="item item-divider">
            Input types for popup keyboard
          </label>
          <label class="item item-input">
            <span class="input-label">Text</span>
            <input type="text" ng-model="user.username">
          </label>
          <label class="item item-input">
            <span class="input-label">Password</span>
            <input type="password" ng-model="user.password">
          </label>          
          <label class="item item-input">
            <span class="input-label">Email</span>
            <input type="email">
          </label>
          <label class="item item-input">
            <span class="input-label">Tel</span>
            <input type="tel">
          </label>
          <label class="item item-input">
            <span class="input-label">Number</span>
            <input type="number">
          </label>
          <label class="item item-input">
            <span class="input-label">Date</span>
            <input type="date">
          </label>
          <label class="item item-input">
            <span class="input-label">Month</span>
            <input type="month">
          </label> 
        </div>
      </ion-content>
    </ion-view>
  </script>     
    
  <script id="about.html" type="text/ng-template">
    <ion-view>
      <ion-header-bar class="bar-positive">
        <button class="button button-icon button-clear ion-navicon" ng-click="toggleLeft()"></button>
        <h1 class="title">About</h1>
      </ion-header-bar>

      <ion-content class="padding">
        <div class="card">
          <div class="item">
            <h3>本测试demo由徐杰开发设计,仅供参考</h3>
            <p><a href="http://www.webdoes.com" target="_blank">联系他</a></p>
          </div>
        </div>
      </ion-content>
    </ion-view>
  </script>    

  <script id="modal.html" type="text/ng-template">
    <div class="modal">
      <ion-header-bar class="bar bar-header bar-positive">
        <h1 class="title">咨询</h1>
        <button class="button button-clear button-primary" ng-click="modal.hide()">取消</button>
      </ion-header-bar>
      
      <ion-content class="padding">
        <div class="list">
          <label class="item item-input">
            <span class="input-label">标题</span>
            <input type="text">
          </label>
          <label class="item item-input">
            <span class="input-label">内容</span>
            <textarea rows="4"></textarea>
          </label>
        </div>
        <button class="button icon icon-right ion-arrow-right-c button-balanced button-block">提交</button>
      </ion-content>
    </div>
  </script>  
      
</body>
</html>

核心代码app.js如下:

angular.module('ionicApp', ['ionic'])

.config(function ($stateProvider, $urlRouterProvider) {

  $stateProvider
    .state('menu', {
      url: "/menu",
      abstract: true,
      templateUrl: "menu.html",
      controller: 'MenuCtrl'
    })
    .state('menu.tabs', {
      url: "/tab",
      views: {
        'menuContent' :{
          templateUrl: "tabs.html"
        }
      }
    })
    .state('menu.tabs.buttons', {
      url: "/buttons",
      views: {
        'buttons-tab': {
          templateUrl: "buttons.html",
          controller: 'ButtonsTabCtrl'
        }
      }
    })
    .state('menu.tabs.list', {
      url: "/list",
      views: {
        'list-tab': {
          templateUrl: "list.html",
          controller: 'ListCtrl'
        }
      }
    })
    .state('menu.tabs.item', {
      url: "/item",
      views: {
        'list-tab': {
          templateUrl: "item.html"
        }
      }
    })
    .state('menu.tabs.testItem', {
      url: "/testItem",
      views: {
        'buttons-tab': {
          templateUrl: "testItem.html"
        }
      }
    })
    .state('menu.tabs.form', {
      url: "/form",
      views: {
        'form-tab': {
          templateUrl: "form.html"
        }
      }
    })
    .state('menu.keyboard', {
      url: "/keyboard",
      views: {
        'menuContent': {
          templateUrl: "keyboard.html"
        }
      }
    })
    .state('menu.slidebox', {
      url: "/slidebox",
      views: {
        'menuContent': {
          templateUrl: "slidebox.html",
          controller: 'SlideboxCtrl'
        }
      }
    })
    .state('menu.about', {
      url: "/about",
      views: {
        'menuContent': {
          templateUrl: "about.html"
        }
      }
    });

  $urlRouterProvider.otherwise("menu/tab/buttons");

})

.controller('ListCtrl', function ($scope) {

  $scope.data = {
    showDelete: false
  };

  $scope.itemButtons = [
    {
      text: 'Delete',
      type: 'button-assertive',
      onTap: function (item) {
        alert('Delete Item: ' + item.id + ' ?');
      }
    }
  ];

  $scope.onItemDelete = function (item) {
    $scope.items.splice($scope.items.indexOf(item), 1);
  };
      $scope.items = [
        {
          id: 1,
          title:'慢性鼻炎怎么预防?'
        },
        {
          id: 2,
          title:'高血压如何预防?'
        },
        {
          id: 3,
          title:'冠心病如何有效治疗?'
        },
        {
          id: 4,
          title:'高血压如何预防?'
        }
      ];


})

.controller('ButtonsTabCtrl', function ($scope, $ionicPopup, $ionicActionSheet, $ionicModal) {
    $scope.showPopup = function () {
     $ionicPopup.alert({
       title: 'Popup',
       content: 'This is ionic popup alert!'
     });
    };
    $scope.showActionsheet = function () {
        $ionicActionSheet.show({
          titleText: 'Ionic ActionSheet',
          buttons: [
            {
              text: 'Facebook'
            },
            {
              text: 'Twitter'
            },
          ],
          destructiveText: 'Delete',
          cancelText: 'Cancel',
          cancel: function () {
            console.log('CANCELLED');
          },
          buttonClicked: function (index) {
            console.log('BUTTON CLICKED', index);
            return true;
          },
          destructiveButtonClicked: function () {
            console.log('DESTRUCT');
            return true;
          }
        });
    };
      $scope.testItems = [
        {
          id: 1,
          title:'慢性鼻炎怎么预防?'
        },
        {
          id: 2,
          title:'高血压如何预防?'
        },
        {
          id: 3,
          title:'冠心病如何有效治疗?'
        },
        {
          id: 4,
          title:'高血压如何预防?'
        }
      ];
    $ionicModal.fromTemplateUrl('modal.html', function (modal) {
        $scope.modal = modal;
      }, {
        animation: 'slide-in-up'
      });
})

.controller('SlideboxCtrl', function($scope, $ionicSlideBoxDelegate) {
  $scope.nextSlide = function() {
    $ionicSlideBoxDelegate.next();
  }             
})              

.controller('MenuCtrl', function($scope, $ionicSideMenuDelegate, $ionicModal) {
  $scope.toggleLeft = function() {
    $ionicSideMenuDelegate.toggleLeft();
  };
              
  $ionicModal.fromTemplateUrl('modal.html', function (modal) {
    $scope.modal = modal;
  }, {
    animation: 'slide-in-up'
  });
 })

  
 .controller('AppCtrl', function() {

  ionic.Platform.ready(function() {

  });

 });

发布:

Now we can tell cordova to generate our release build:

$ cordova build --release android

在IOS中也是一样,不过IOS要打包成ipa,需要开发者账号,有兴趣朋友求提供下,谢谢!

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值