Ionic page transition not working to page with pus

2020-04-18 09:25发布

问题:

I implemented android push reception in my app, and it works well as long as the app starts at that page. But if you navigate to the inbox page where the push notifications are implemented the transition doesn't work.

The transition worked well without the push implementation.

I wonder if someone has had a similar problem implementing features.

.controller('BuzonMenuCtrl', function($scope, $window, $state, $ionicPlatform) {
  $scope.botonBuzon = function(){
    $state.go('buzon');
  };
})

.controller('BuzonCtrl', function($scope, $rootScope, $window, $ionicActionSheet, $ionicPopup, $state, $http, dataFactory, pushFactory) {

  // Activacion de la funcionalidad push
  pushFactory.funcionalidadPush();

}

factorys.js

.factory('pushFactory', ['$rootScope','$http','$state','$ionicLoading','$ionicPlatform','$cordovaPush','dataFactory',
                          function($rootScope,$http,$state,$ionicLoading,$ionicPlatform,$cordovaPush,dataFactory) {

  /* Objeto del factory */
  var fac = {};

  fac.funcionalidadPush = function(){
    if (ionic.Platform.isAndroid()){
      var androidConfig = {
        "senderID": "94XXXXXXXXXX",
        "ecb": "casosPush"
      };

      $rootScope.data.pushplatform = "gcm";
      alert('Entro en modo Android');

    };

    if (ionic.Platform.isIOS()){
      alert('Entro en modo iOS');
    };

    $ionicPlatform.ready(function() {
      $cordovaPush.register(androidConfig).then(function(result) {
        // Success
      }, function(err) {
        // Error
      })

      window.casosPush = function (notification) {
        switch(notification.event) {
          case 'registered':
            if (notification.regid.length > 0 ) {
              alert('registration ID = ' + notification.regid);
              $rootScope.data.token = notification.regid;

            }
            break;

          case 'message':
            // this is the actual push notification. its format depends on the data model from the push server
            //alert('message = ' + notification.message + ' msgCount = ' + notification.msgcnt);
            $rootScope.mensajes.push(notification);
            break;

          case 'error':
            alert('GCM error = ' + notification.msg);
            break;

          default:
            alert('An unknown GCM event has occurred');
            break;
        }
      };

      // WARNING: dangerous to unregister (results in loss of tokenID)
      $cordovaPush.unregister(options).then(function(result) {
        // Success!
      }, function(err) {
              // Error
      })

    }, false);
  };


  return fac;

}]);

App.js

angular.module('notPush', ['ionic', 'ngCordova', 'notPush.controllers'])

.run(function($ionicPlatform) {
  $ionicPlatform.ready(function() {
    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }
    if(window.StatusBar) {
      StatusBar.styleDefault();
    }
  });
})

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

  $stateProvider

  .state('splash', {
    url: '/splash',
    templateUrl: 'templates/splash.html',
    controller: 'SplashCtrl'
  })

  .state('buzonMenu', {
    url: '/buzonMenu',
    templateUrl: 'templates/buzonMenu.html',
    controller: 'BuzonMenuCtrl'
  })

  .state('buzon', {
    url: '/buzon',
    templateUrl: 'templates/buzon.html',
    controller: 'BuzonCtrl'
  })

  // If none of the above states are matched, use this as the fallback:
  $urlRouterProvider.otherwise('/buzonMenu');

});

EDIT

As suggested in the comments I tried

$window.location.reload(true);

which doesn't do anything except to make the screen blink, and also

$state.go($state.current, {}, {reload: true});

which attemps to reload the page but only in a corrupt state, it loads the white background and the buttons (without color) but nothing else.

EDIT 2 Some clarifications:

  1. The code for push notifications is written inside the buzon_page controller, which is the page that is having trouble.
  2. When I say "the transition doesn't work" I mean that the page doesn't load, but all the alerts of that page are still triggered, and the Push Token is still retrieved. Is a visual problem, the view doesn't load.
  3. The problem is not related to HTTP calls because they are currently commented.

EDIT 3

I moved the notifications code to a factory instead of having it inside the controller (as it should be, I guess) but there is no improvement.

I'm adding the result of adb logcat during the issue. There are 2 things that cought my attention:

  1. It shows a "ReferenceError: options is not defined" at factorys.js
  2. It shows some OpenGLRenderer issue.

    1219             AudioTrack  W  AUDIO_OUTPUT_FLAG_FAST denied by client   
    2531             PushPlugin  V  execute: action=register
    2531             PushPlugin  V  execute: data=[{"senderID":ID DELETED FOR PRIVACY ISSUES,"ecb":"casosPush"}]
    2531             PushPlugin  V  execute: jo={"senderID":ID DELETED FOR PRIVACY ISSUES,"ecb":"casosPush"}
    2531             PushPlugin  V  execute: ECB=casosPush senderID=ID DELETED FOR PRIVACY ISSUES
    2531           GCMRegistrar  D  resetting backoff for ID DELETED FOR PRIVACY ISSUES
    1219   InputMethodManager..  W  Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@df31fbd attribute=null, token = a
                                   ndroid.os.BinderProxy@28f2dc02
    2531           GCMRegistrar  V  Registering app ID DELETED FOR PRIVACY ISSUES of senders ID DELETED FOR PRIVACY ISSUES
    2531   SystemWebChromeCli..  D  file:///android_asset/www/lib/ionic/js/ionic.bundle.js: Line 20243 : ReferenceError: options is not defined
    2531   SystemWebChromeCli..  D  at file:///android_asset/www/js/factorys.js:214:31
    2531   SystemWebChromeCli..  D  at file:///android_asset/www/lib/ionic/js/ionic.bundle.js:44687:19
    2531   SystemWebChromeCli..  D  at Object.ionic.Platform.ready (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:2120:9)
    2531   SystemWebChromeCli..  D  at Object.self.ready (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:44685:26)
    2531   SystemWebChromeCli..  D  at Object.fac.funcionalidadPush (file:///android_asset/www/js/factorys.js:166:20)
    2531   SystemWebChromeCli..  D  at new <anonymous> (file:///android_asset/www/js/controllers.js:440:15)
    2531   SystemWebChromeCli..  D  at invoke (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:12821:17)
    2531   SystemWebChromeCli..  D  at Object.instantiate (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:12829:27)
    2531   SystemWebChromeCli..  D  at file:///android_asset/www/lib/ionic/js/ionic.bundle.js:17098:28
    2531   SystemWebChromeCli..  D  at self.appendViewElement (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:48110:24)
    2531               chromium  I  [INFO:CONSOLE(20243)] "ReferenceError: options is not defined
    2531               chromium  I  at file:///android_asset/www/js/factorys.js:214:31
    2531               chromium  I  at file:///android_asset/www/lib/ionic/js/ionic.bundle.js:44687:19
    2531               chromium  I  at Object.ionic.Platform.ready (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:2120:9)
    2531               chromium  I  at Object.self.ready (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:44685:26)
    2531               chromium  I  at Object.fac.funcionalidadPush (file:///android_asset/www/js/factorys.js:166:20)
    2531               chromium  I  at new <anonymous> (file:///android_asset/www/js/controllers.js:440:15)
    2531               chromium  I  at invoke (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:12821:17)
    2531               chromium  I  at Object.instantiate (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:12829:27)
    2531               chromium  I  at file:///android_asset/www/lib/ionic/js/ionic.bundle.js:17098:28
    2531               chromium  I  at self.appendViewElement (file:///android_asset/www/lib/ionic/js/ionic.bundle.js:48110:24)", source: file:///android_asset/www/lib/ionic
                                   /js/ionic.bundle.js (20243)
    1604                    GCM  D  GcmService start Intent { act=com.google.android.c2dm.intent.REGISTER pkg=com.google.android.gms cmp=com.google.android.gms/.gcm.GcmServi
                                   ce (has extras) } com.google.android.c2dm.intent.REGISTER
    2531   GCMBroadcastReceiver  V  onReceive: com.google.android.c2dm.intent.REGISTRATION
    2531           GCMRegistrar  V  Setting the name of retry receiver class to com.plugin.gcm.CordovaGCMBroadcastReceiver
    2531   GCMBroadcastReceiver  V  GCM IntentService class: com.plugin.gcm.GCMIntentService
    2531   GCMBaseIntentService  V  Acquiring wakelock
    2531   GCMBaseIntentService  V  Intent service name: GCMIntentService-GCMIntentService-1
    2531           GCMRegistrar  V  Registering receiver
    2531   GCMBaseIntentService  D  handleRegistration: registrationId = TOKEN DELETED FOR PRIVACY ISSUES, error = null, unregistered = null
    2531           GCMRegistrar  D  resetting backoff for ID DELETED FOR PRIVACY ISSUES
    2531           GCMRegistrar  V  Saving regId on app version 10
    2531       GCMIntentService  V  onRegistered: TOKEN DELETED FOR PRIVACY ISSUES
    2531       GCMIntentService  V  onRegistered: {"event":"registered","regid":TOKEN DELETED FOR PRIVACY ISSUES}
    2531             PushPlugin  V  sendJavascript: javascript:casosPush({"event":"registered","regid":TOKEN DELETED FOR PRIVACY ISSUES})
    2531   GCMBaseIntentService  V  Releasing wakelock
    2531          EGL_emulation  W  eglSurfaceAttrib not implemented
    2531         OpenGLRenderer  W  Failed to set EGL_SWAP_BEHAVIOR on surface 0xa4cdd7e0, error=EGL_SUCCESS
    1219             AudioTrack  W  AUDIO_OUTPUT_FLAG_FAST denied by client
    1219   InputMethodManager..  W  Window already focused, ignoring focus gain of: com.android.internal.view.IInputMethodClient$Stub$Proxy@35215d0a attribute=null, token = 
                                   android.os.BinderProxy@28f2dc02
    

回答1:

I solved the problem thanks to the help in the comments, so I'm going to write the solution here.

The comment suggested this code so that the push notifications were activated as soon as the app starts.

I'll add here my own code just in case, the alerts and $rootScope variables are for testing purposes.

/* 
   app.js
*/
angular.module('notPush', ['ionic', 'notPush.controllers', 'notPush.factorys'])

.run(function($ionicPlatform,$rootScope) {
  $ionicPlatform.ready(function() {

    if(window.cordova && window.cordova.plugins.Keyboard) {
      cordova.plugins.Keyboard.hideKeyboardAccessoryBar(true);
    }

    if(window.StatusBar) {
      StatusBar.styleDefault();
    }

    $rootScope.mensajes = [];

    // Push code
    try{
      var pushNotification = window.plugins.pushNotification;
    } catch (ex){

    }
    var successfn = function(result){
      alert("Success: " + result);
    };
    var errorfn   = function(result){
      window.alert("Error: " + result);
    };
    window.casosPush = function(notification){
      switch (notification.event){
        case 'registered':
          if (notification.regid.length > 0){
            alert('registration ID = ' + notification.regid);
          }
          break;

        case 'message':
          alert(JSON.stringify([notification]));
          $rootScope.mensajes.push(notification);
          break;

        case 'error':
          alert('GCM error = ' + notification.msg);
          break;

        default:
          alert('An unknown GCM event has occurred');
          break;
      }
    };
    try{
      pushNotification.register(
        successfn,
        errorfn,
        {
          "senderID": "94XXXXXXXXXX",
          "ecb"     : "window.casosPush"
        }
      );
    } catch(notification){

    } 
  });
})

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

  $stateProvider

  .state('splash', {
    url: '/splash',
    templateUrl: 'templates/splash.html',
    controller: 'SplashCtrl'
  })

  .state('registro', {
    url: '/registro',
    templateUrl: 'templates/registro.html',
    controller: 'RegistroCtrl'
  })

  .state('buzonMenu', {
    url: '/buzonMenu',
    templateUrl: 'templates/buzonMenu.html',
    controller: 'BuzonMenuCtrl'
  })

  .state('buzon', {
    url: '/buzon',
    templateUrl: 'templates/buzon.html',
    controller: 'BuzonCtrl'
  })

  .state('detallesSimple', {
    url: '/detallesSimple',
    templateUrl: 'templates/detallesSimple.html',
    controller: 'DetallesCtrl'
  })

  .state('detallesDoble', {
    url: '/detallesDoble',
    templateUrl: 'templates/detallesDoble.html',
    controller: 'DetallesCtrl'
  })

  .state('detallesWV', {
    url: '/detallesWV',
    templateUrl: 'templates/detallesWV.html',
    controller: 'DetallesWVCtrl'
  })

  // If none of the above states are matched, use this as the fallback:
  $urlRouterProvider.otherwise('/splash');

});


回答2:

A sample code from a working Ionic project. As an example for how PushPlugin should be initialized.

var exapp = angular.module('exapp',
                  ['ionic',
                   'ui.select2',
                   'exapp.controllers',
                   'exapp.services']);

exapp.run(function($ionicPlatform, $state, Notifications, geo) {
    $ionicPlatform.ready(function() {
    try{
        var pushNotification = window.plugins.pushNotification;
    } catch (ex){

    }
    var successfn = function(result){
        // window.alert("S: " + result);
    };
    var errorfn   = function(result){
        // window.alert("E: " + result);
    };
    window.onCB = function(e){
        switch (e.event){
        case 'registered':
        if (e.regid.length > 0){
            localStorage.setItem('registration_id', e.regid);
        }
        break;
        case 'message':
        if (e.foreground){
            navigator.notification.beep(1);
        }
        $state.go('app.notifications');
        break;
        }
    };
    try{
        pushNotification.register(
        successfn,
        errorfn,
        {
            "senderID": "191919191919191",
            "ecb"     : "window.onCB"
        }
        );
    } catch(e){

    }
    });
});

// States
exapp.config(function($stateProvider, $urlRouterProvider) {
    $stateProvider

    .state('app', {
        url: "/app",
        abstract: true,
        templateUrl: "templates/menu.html",
        controller: 'AppCtrl'
    })

    .state('app.profile', {
        url: "/profile",
        views: {
        'menuContent': {
            templateUrl: "templates/profile.html",
            controller: "ProfileCtrl"
        }
        }
    })

    .state('app.login', {
        url: "/login",
        views: {
        'menuContent' :{
            templateUrl: "templates/login.html",
            controller: 'AuthCtrl'
        }
        }
    });

    // if none of the above states are matched, use this as the fallback
    $urlRouterProvider.otherwise('/app/profile');
});

Provided here just in case the gist becomes unavailable.



回答3:

I had similar problem in my app when i was trying to make a REST call at the same time of view transition. this is because $http promise is interrupting view rendering. This can be taken care of if you wrap your $http call in $timeout because $timeout with no time mentioned will put your $http in queue rather than interrupting current task.

you can do something like

$scope.$on('$cordovaPush:notificationReceived', handleNotification);

handleNotification = function(event, notification){
    $timeout(function(event, notification) {
            switch(notification.event) {
                case 'registered':
                    if (notification.regid.length > 0 ) {
                        alert('registration ID = ' + notification.regid);
                        $scope.regid = notification.regid;
                        var user = { user: 'David', type: 'android', token: notification.regid };
                        $http.post('http://172.16.16.101:8000/tokens', JSON.stringify(user));
                    }
                    break;

                case 'message':
                    // this is the actual push notification. its format depends on the data model from the push server
                    //alert('message = ' + notification.message + ' msgCount = ' + notification.msgcnt);
                    alert(JSON.stringify([notification]));
                    var aux = {title:'',message:'',payload: { valor1:true }}
                    $scope.mensajes.push(notification);
                    break;

                case 'error':
                    alert('GCM error = ' + notification.msg);
                    break;

                default:
                    alert('An unknown GCM event has occurred');
                    break;
            }
        });
}

this is a rough idea that you have to fix and refine to fit your need