본문으로 건너뛰기

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을 사용하며, 다른 두 개는 정말 너무 춥습니다. 더 많은 내용은 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]

꽤 좋죠, 비매품, 증정하지 않습니다~

댓글

아직 댓글이 없습니다

댓글 작성