天天看點

ionic開發跨平台App常見問題

ionic是一個用來快速開發跨平台應用的架構,亮點不少:

  • 學習成本低
  • 對前端開發者來說,學習成本不是很高,如果有接觸過angular,就幾乎沒有什麼學習成本了
  • 簡單易用
  • 強大的CLI,

    start

    ->

    platform

    ->

    serve

    ->

    build

    ->

    emulate

    ->

    run

    ,全套服務指令行完成,不用寫配置檔案,不用F5
  • 元件多而強大
  • 提供了很多強大的現成元件,很容易實作流行的互動效果,比如下拉重新整理(

    ion-refresher

    )、上拉加載/瀑布流(

    ion-infinite-scroll

    )、tabs(

    ion-tabs

    )、側邊欄菜單(

    ion-side-menu

    )等等,隻需要寫一點點代碼,就能實作這些流行效果,比native開發速度快太多了
  • 支援cordova插件
  • 打開了這扇門,意味着我們可以使用大量的原生功能,比如調用相機拍照、響應傳回按鈕、打電話發短信發郵件……都隻要幾行代碼就能搞定
  • 更新速度快
  • 已經是v1.2.4了,快速更新意味着有人維護,bug能被迅速修複

當然,也有缺陷,否則就沒有這篇筆記了,如下:

  • 新版本不完全向後相容
  • 不相容沒關系,給個詳細文檔說明下也行啊,沒有
  • bug難以定位
  • angular+cordova+ionic+javascript,發現問題後,很難确定是哪塊的問題
  • 性能優化難
  • 動畫卡頓,低端機體驗更差,而優化措施一般都是建議少用動畫少用陰影少用漸變……但是,不用實在太醜,而且與native應用體驗差太多
  • 其它
  • 奇奇怪怪的問題找不到答案,大半夜的翻stackoverflow……

一.jsonp跨域,php服務怎麼寫

P.S.這是angular的問題,當時沒整理筆記,後來就忘記了遇到過這麼個問題

angular的$http可以發送jsonp請求,用法類似于jQuery,如下:

// 請求資料
$http.jsonp(sUrl).success(function(res){
    // ...
}).error(function(err){
    // ...
});           

sUrl

有特殊要求,必須帶上

callback

參數,而且參數值隻能是

JSON_CALLBACK

,angular文檔:

Relative or absolute URL specifying the destination of the request. The name of the callback should be the string JSON_CALLBACK.

例如:

而問題是:php服務怎麼寫?直接傳回用

JSON_CALLBACK()

包裹的json資料?

不對,因為真正請求的url中

callback !== JSON_CALLBACK

,被angular偷偷(文檔沒有說明)替換掉了,是以背景需要這樣寫:

<?php
if (strpos($_SERVER["REQUEST_URI"], 'callback')) {
    $res = json_encode($res);
    // echo $_SERVER["REQUEST_URI"];
    // /angular/test/http/main.php?callback=angular.callbacks._0
    // $res = 'JSON_CALLBACK('.$res.')';
    // 錯的
    $res = $_GET['callback'].'('.$res.')';
}
?>           

當然,這是get的情況,比較簡單,如果是post,還需要通過别的方式取

callback

,完整例子如下:

<?php
// get
if ($_SERVER['REQUEST_METHOD'] === 'GET') {
    $res = '{';

    // arg
    if (isset($_GET['arg'])) {
        $res .= '"arg": "'.$_GET['arg'].'", ';
    }
    // method
    if (strpos($_SERVER["REQUEST_URI"], 'callback')) {
        // echo $_SERVER["REQUEST_URI"];
        // /angular/test/http/main.php?callback=angular.callbacks._0
        $res .= '"arg": "'.$_GET['arg'].'", ';
        $res .= '"method": "jsonp"}';
        // $res = 'JSON_CALLBACK('.$res.')';
        // 錯的
        $res = $_GET['callback'].'('.$res.')';
    }
    else {
        $res .= '"method": "get"}';
    }

    echo $res;
}
// post
else if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    // 直接拿拿不到,因為傳過來的是json串
    // echo $_POST['arg'];
    $jsonArg = file_get_contents('php://input');
    if (isset($jsonArg)) {
        echo substr($jsonArg, 0, strlen($jsonArg) - 1).', "method": "post"}';
    }
    else {
        echo '{"method": "post"}';
    }
}
?>           

二.ion-content的阻尼回彈效果沒了

ionic v1.2取消了

ion-content

預設的阻尼回彈效果,明明一模一樣的代碼,就是沒有回彈效果,後來發現是版本更新的鍋,翻了很久後,在官方部落格的評論裡找到了答案:

Great news, thank you! It seems that the “has-bouncing=’true'” does not work with the native scroll, is it correct? I managed though to have it again by going to back go js scroll (overflow-scroll=”false”)

I only checked in the browser so if any one can confirm that with native scrolling removes bouncing that would be great.

I need this feature for a custom ‘pull refresh’ method I had.

也就是說,v1.2之後想要有阻尼回彈效果,需要這麼做:

三.多個view之間的資料共享

也就是多個controller之間的資料共享(一般不同view對應不同controller)問題,當然,最簡單的方法是用全局變量(

$rootScope

),但這樣不好,更合理的方式是自己寫個

service

或者

factory

,提供資料存取接口,在需要的地方依賴注入即可,比如:

.service('DataServ', ['$http', 'UIServ', function($http, UIServ) {
    // ...
    // 字典
    var oDir = {
        // key: value
    };

    function save(val) {
        var sKey = Date.now() + '';
        oDir[sKey] = val;
        return sKey;
    }

    function get(sKey) {
        return oDir[sKey];
    }

    return {
        // ...
        save: save,
        get: get
    };
}]);           

然後通過url傳遞

sKey

即可實作資料共享,很幹淨

四.通知視圖更新

在模闆中寫好了資料展示,但如果打開頁面後資料還沒到,模闆解析完了,由于沒有資料顯示空白頁,過了一會兒資料到了,發現視圖沒有更新,仍然是一片空白,比如:

<!-- html -->
<p ng-cloak>{{data}}</p>

// js
app.controller('MainCtrl', ['$scope', 'DataServ', function($scope, DataServ) {
    // ...
    setTimeout(function() {
        // ...
        $scope.data = 'data';
    })
}]);           

因為給data指派的操作跑到了controller作用域外,此時需要手動通知視圖更新,如下:

// ...
$scope.data = 'data';
$scope.$apply();           

當然,一般不需要手動通知,即便是異步傳回的資料,因為這裡隻與作用域有關,總之,如果發現視圖需要手動更新,添上

$apply

就好了

五.php原生xml擴充如何擷取裡的内容

rss格式中會有

<content: encoded>

标簽,直接取

content

取不到,需要特殊的方式:

$content = (string)$item->children("content", true);
// $encodedContent = $content->encoded;
// $content->encoded傳回轉義過的html,比如把&amp;轉成&,一般用于<pre>直接展示           

當然,前提是使用原生xml擴充(

$xml = simplexml_load_file($url);

)解析xml才會遇到這個問題,更多用法請檢視php – How to parse CDATA HTML-content of XML using SimpleXML? – Stack Overflow

六.在浏覽器中打開外部頁面

需要使用一個cordova插件,cd進項目檔案夾,然後:

安裝完成後就可以調用了,不用修改配置檔案,不用引入其他js,如下:

// openInBrowser
window.open(‘http://example.com’, ‘_system’);   Loads in the system browser
window.open(‘http://example.com’, ‘_blank’);    Loads in the InAppBrowser
window.open(‘http://example.com’, ‘_blank’, ‘location=no’); Loads in the InAppBrowser with no location bar
window.open(‘http://example.com’, ‘_self’); Loads in the Cordova web view
// test
window.open(url, '_system'); // 系統預設浏覽器
// window.open(url, '_blank');  // 很醜的安卓内置浏覽器
// window.open(url, '_self');  // 同上           
一般都用         _system                ,另外兩個實在太醜,更多内容請檢視Cordova InAppBrowser Plugin Example using ionic framework

  

  
      
最近新發現 修改後的浏覽器插件,可以用圖檔自定義部分樣式
           
github位址:https://github.com/initialxy/cordova-plugin-themeablebrowser
            
cordova plugin add cordova-plugin-themeablebrowser
           

七.splash screen黑屏白屏

P.S.黑屏白屏其實是同一個問題,但這個問題相當難解決,筆者花了快1天才搞定

ionic預設內建了

splashscreen

插件,這個cordova插件效果不是很完美,預設配置隻在首次打開app時顯示splash screen,但實際效果是:

When the app starts the splash screen shows for a few seconds as expected, and then the screen goes black for @1 second and then white for @2 seconds and then the main app page appears.

Is there any way to prevent the black and white pages appearing? I read somewhere that a black page appears when there is no splash page but I do have a splash page and it appears fine.

在stackoverflow找到了這個問題描述,簡直太貼切了,但是單靠問題下面的回答無法解決白屏問題,還需要改配置檔案

最初發現的現象是黑屏(把上面英文描述裡的white換成黑),後來找到了原因:主視圖容器

ion-nav-view

是空的,而它的背景色是

#000

,是以修複方法是給裡面塞個

ion-view

<!-- 内容 -->
<ion-nav-view>
    <!-- 防止啟動時黑屏 -->
    <ion-view></ion-view>
</ion-nav-view>           

或者添css,把

ion-nav-view

的背景色改成白色。但問題還沒解決,黑屏問題變成白屏問題了,解決方案比較麻煩

  1. 把splashscreen插件降級到v2.0.0

    v2.0.0之後的版本有bug,目前(2016/1/9)自帶的版本是v3.0.0。先cd到項目檔案夾,然後指令行:

    // 删掉現有版本
    cordova plugin rm cordova-plugin-inappbrowser
    // 安裝v2.0.0
    cordova plugin add cordova-plugin-inappbrowser
    
          
  2. 改配置檔案MyApp/config.xml

    <preference name="SplashScreen" value="screen"/>
    <preference name="AutoHideSplashScreen" value="false"/>
    <preference name="auto-hide-splash-screen" value="false"/>
    <preference name="ShowSplashScreenSpinner" value="false"/>
    <preference name="SplashMaintainAspectRatio" value="true" />
    <preference name="SplashShowOnlyFirstTime" value="false"/>
    <preference name="SplashScreenDelay" value="10000"/>
    
          

    取消自動隐藏(改為代碼控制隐藏),把持續時間改為較大的值(10秒),設定每次打開應用都顯示splash screen

    P.S.預設隻有

    SplashScreen

    SplashScreenDelay

    ,需要把其它的(

    SplashMaintainAspectRatio

    可選)都添上

  3. 改app.js

    手動隐藏splash screen,在run裡面添上

    .run(['$rootScope', function($rootScope) {
            // init
            // $rootScope.isLoading = false;
    
            // hide splash immediately
            if(navigator && navigator.splashscreen) {
                navigator.splashscreen.hide();
            }
        });
    }])
    
          

    這樣就好了,不要延時調用hide,否則仍然會出現白屏(有些解決方案要求$timeout 50毫秒hide,仍然會出現白屏,不要這樣做)

最怨念的問題結束了,看似簡單的功能,想要有完美的原生體驗卻很難,奇奇怪怪的問題很難解決,目前可行的解決方案可能過段時間就不行了,可以檢視White page showing after splash screen before app load感受一下

八.安卓版本簽名釋出

各種簽名方法都過時了,目前(2016/1/9)可以用的簽名方法如下:

  1. 在MyApp\platforms\android建立keystore

    具體步驟請檢視:Ionic toturial for building a release.apk

  2. 建立release-signing.properties檔案

    具體步驟請檢視:How to automatically sign your Android apk using Ionic framework and Crosswalk

  3. build

    cd到項目檔案夾,然後指令行

    ionic build --release android

    ,成功後會生成2個東西,在MyApp\platforms\android\build\outputs\apk下,分别是android-armv7-release.apk和android-x86-release.apk,一般平闆和PC用x86,手機用arm7,如果要上傳google play的話,2個都要傳,下載下傳時有自動識别

至于crosswalk,提供了chrome核心,能讓低端機支援高端東西,但會讓apk 變大很多(3.5M->23M),添上crosswalk後,感覺。。。嗯,變卡了,但為了支援低端機使用者,一般都會添上crosswork 

繼續閱讀