メインコンテンツへ移動

Ionic でクロスプラットフォーム App 開発時のよくある問題

無料2016-01-09#Ionic#Solution#ionic白屏#ionic黑屏#ionic闪屏#ionic splash screen#ionic列表回弹#ionic数据共享#ionic安卓签名#ionic性能优化

何と言えばよいのか、迅速な開発は素晴らしいですが、後遺症は痛いです。

はじめに

ionic はクロスプラットフォームアプリケーションの迅速な開発のためのフレームワークで、多くの亮点があります:

  • 学習コストが低い

フロントエンド開発者にとって、学習コストはそれほど高くありません。angular に触れたことがあれば、ほぼ学習コストはありません

  • 簡単で使いやすい

強力な CLI で、start->platform->serve->build->emulate->run、一連のサービスをコマンドラインで完了でき、設定ファイルを書く必要も F5 も不要

  • コンポーネントが多く強力

多��の強力な既製コンポーネントを提供しており、流行のインタラクション効果を簡単に実装できます。例えば、プルダウンリフレッシュ(ion-refresher)、プルアップロード/ウォーターフォールフロー(ion-infinite-scroll)、tabs(ion-tabs)、サイドバーメニュー(ion-side-menu)などで、少しのコードを書くだけでこれらの流行効果を実装でき、native 開発よりもはるかに速いです

  • cordova プラグインをサポート

この扉を開くことで、大量のネイティブ機能を使用できるようになります。例えば、カメラを呼び出して撮影、戻るボタンに応答、電話をかける、SMS を送信、メールを送信……すべて数行のコードで解決できます

  • 更新速度が速い

2015/11/1 は v1.1.0、現在(2016/1/9)はすでに v1.2.4 です。迅速な更新はメンテナンス担当者がおり、バグが迅速に修正されることを意味します

もちろん、欠陥もあります。そうでなければこのノートはありません。以下:

  • 新バージョンは完全に後方互換ではない

互換性がなくても、詳細なドキュメントで説明してくれればよいのですが、ありません

  • バグの特定が困難

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.

例:

var sUrl = http://www.ayqy.net/app/rsshelper/index.php?callback=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 以降でダンピングリバウンド効果を持たせるには、このようにする必要があります:

<ion-content overflow-scroll="false" has-bouncing="true"></ion-content>

三.複数の 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 拡張で<content: encoded>の内容を取得する方法

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 して、その後:

ionic plugin add cordova-plugin-inappbrowser

インストール完了後、呼び出し可能で、設定ファイルの変更も他の js の導入も不要:

// openInBrowser
window.open('http://example.com', '_system');   システムブラウザでロード
window.open('http://example.com', '_blank');    InAppBrowser でロード
window.open('http://example.com', '_blank', 'location=no'); ロケーションバーなしの InAppBrowser でロード
window.open('http://example.com', '_self'); Cordova web view でロード
// test
window.open(url, '_system'); // システムデフォルトブラウザ
// window.open(url, '_blank');  // 非常に醜いアンドロイド内蔵ブラウザ
// window.open(url, '_self');  // 同上

一般的に_systemを使用し、他の 2 つは本当に醜すぎます。詳細は Cordova InAppBrowser Plugin Example using ionic framework を参照してください

七.splash screen の黒屏白屏

P.S. 黒屏白屏は実際には同じ問題ですが、この問題は非常に解決が困難で、筆者はほぼ 1 日かけて解決しました

ionic はデフォルトでsplashscreenプラグインを統合しており、この cordova プラグインの効果は完璧ではありません。デフォルト設定ではアプリを初めて開いた時のみ 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 以降のバージョンにはバグがあり、現在(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. デフォルトではSplashScreenSplashScreenDelayのみ、その他(SplashMaintainAspectRatioはオプション)を追加する必要

  1. 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 を参照

  1. release-signing.properties ファイルを作成

具体的な手順は:How to automatically sign your Android apk using Ionic framework and Crosswalk を参照

  1. 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 を追加します

九.まとめ

何と言えばよいのか、迅速な開発は素晴らしいですが、後遺症は痛いです。

筆者は 1 月 3 日から開始、1 月 8 日正午に v1.0.0 をリリース、写真は以下の通り:

[caption id="attachment_933" align="alignnone" width="625"]rsshelper rsshelper[/caption]

[caption id="attachment_934" align="alignnone" width="625"]rsshelper rsshelper[/caption]

なかなか良いでしょう、非売品、プレゼントしません〜

コメント

コメントはまだありません

コメントを書く