1. 程式人生 > >ionic框架對Android返回鍵的處理

ionic框架對Android返回鍵的處理

       在HybridApp移動跨平臺開發中,android平臺會遇到一些比較特殊並難以解決的問題,這些問題在原生應用開發中很easy, Android的返回鍵處理就是問題之一,假如我們要實現一個在很多App中都有的在主頁按返回鍵彈出對話方塊提示使用者退出應用的功能,在原生應用開發中是很容易的,只要在onKeyUp事件裡面對返回鍵事件進行處理就可以了。按2次返回鍵退出應用的Java程式碼如下:

private long exitTime = 0;

@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if(keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN){   
        if((System.currentTimeMillis()-exitTime) > 2000){  
            Toast.makeText(getApplicationContext(), "再按一次退出程式", Toast.LENGTH_SHORT).show();                                
            exitTime = System.currentTimeMillis();   
        } else {
            finish();
            System.exit(0);
        }
        return true;   
    }
    return super.onKeyDown(keyCode, event);
}

      但在使用了PhoneGap的HTML5應用程式中,事情就沒有這麼簡單了,首先WebView接管了返回鍵的事件,你無法在Java層處理返回鍵,除非改Cordova框架的程式碼,但這樣顯然是不合適的,會帶來維護問題,也不符合一般的開發規範。即使我們可以修改Cordova原始碼,同時處理好按返回鍵Webview回退上一頁和在首頁時彈出處理提示,也是很困難的。

      在深入分析ionic框架原始碼,在與ionic論壇的國外開發者交流後,終於找到了一個比較後的解決方法。Ionic作為目前國外比較活躍的HybridApp移動開發框架,對Android平臺的返回鍵的處理是有比較合理的解決方案的。ionic框架對android返回鍵處理的原始碼如下:

返回鍵優先順序定義,主要用途是返回鍵行為的優先順序定義,例如當有彈出框時(優先順序400),按返回鍵取消彈出框,不回退頁面(優先順序100)

var PLATFORM_BACK_BUTTON_PRIORITY_VIEW = 100;
var PLATFORM_BACK_BUTTON_PRIORITY_SIDE_MENU = 150;
var PLATFORM_BACK_BUTTON_PRIORITY_MODAL = 200;
var PLATFORM_BACK_BUTTON_PRIORITY_ACTION_SHEET = 300;
var PLATFORM_BACK_BUTTON_PRIORITY_POPUP = 400;
var PLATFORM_BACK_BUTTON_PRIORITY_LOADING = 500;
註冊返回鍵處理動作,我們自己對返回鍵的處理需要在這裡實現了,注意返回的是一個函式,呼叫這個函式將取消本次事件註冊。
        /**
         * @ngdoc method
         * @name $ionicPlatform#registerBackButtonAction
         * @description
         * Register a hardware back button action. Only one action will execute
         * when the back button is clicked, so this method decides which of
         * the registered back button actions has the highest priority.
         *
         * For example, if an actionsheet is showing, the back button should
         * close the actionsheet, but it should not also go back a page view
         * or close a modal which may be open.
         *
         * @param {function} callback Called when the back button is pressed,
         * if this listener is the highest priority.
         * @param {number} priority Only the highest priority will execute.
         * @param {*=} actionId The id to assign this action. Default: a
         * random unique id.
         * @returns {function} A function that, when called, will deregister
         * this backButtonAction.
         */
        $backButtonActions: {},
        registerBackButtonAction: function(fn, priority, actionId) {

          if(!self._hasBackButtonHandler) {
            // add a back button listener if one hasn't been setup yet
            self.$backButtonActions = {};
            self.onHardwareBackButton(self.hardwareBackButtonClick);
            self._hasBackButtonHandler = true;
          }

          var action = {
            id: (actionId ? actionId : ionic.Utils.nextUid()),
            priority: (priority ? priority : 0),
            fn: fn
          };
          self.$backButtonActions[action.id] = action;

          // return a function to de-register this back button action
          return function() {
            delete self.$backButtonActions[action.id];
          };
        },
回到我們剛開始提出的問題,在主頁增加按返回鍵提出退出應用,在其它頁面正常返回上個頁面,只要註冊一個處理事件就可以了,程式碼如下:
.run(['$ionicPlatform', '$ionicPopup','$rootScope','$location', function ($ionicPlatform, $ionicPopup, $rootScope, $location) {
       
        //主頁面顯示退出提示框
        $ionicPlatform.registerBackButtonAction(function (e) {

            e.preventDefault();

            function showConfirm() {
                var confirmPopup = $ionicPopup.confirm({
                    title: '<strong>退出應用?</strong>',
                    template: '你確定要退出應用嗎?',
                    okText: '退出',
                    cancelText: '取消'
                });

                confirmPopup.then(function (res) {
                    if (res) {
                        ionic.Platform.exitApp();
                    } else {
                        // Don't close
                    }
                });
            }

            // Is there a page to go back to?
            if ($location.path() == '/home' ) {
                showConfirm();
            } else if ($rootScope.$viewHistory.backView ) {
                console.log('currentView:', $rootScope.$viewHistory.currentView);
                // Go back in history
                $rootScope.$viewHistory.backView.go();
            } else {
                // This is the last page: Show confirmation popup
                showConfirm();
            }

            return false;
        }, 101);

    }])