0

My ionic2 app is taking like 15 seconds to start in a device. I tried all the recommendation (minify, uglify, enableProd, --prod --release, etc) My final apk is 4.3MB

The app doesn't have any image except from the icon and from the splashcreen, It has more less 20 screens, but just text and list and buttons (it's a payment app so nothing weird)

My package.json is:

{
  "name": "xxxxx",
  "author": "xxxx",
  "homepage": "http://ionicframework.com/",
  "private": true,
  "scripts": {
    "ionic:build": "ionic-app-scripts build",
    "ionic:serve": "ionic-app-scripts serve"
  },
  "dependencies": {
    "@angular/common": "2.2.1",
    "@angular/compiler": "2.2.1",
    "@angular/compiler-cli": "2.2.1",
    "@angular/core": "2.2.1",
    "@angular/forms": "2.2.1",
    "@angular/http": "2.2.1",
    "@angular/platform-browser": "2.2.1",
    "@angular/platform-browser-dynamic": "2.2.1",
    "@angular/platform-server": "2.2.1",
    "@ionic/cloud-angular": "^0.8.0",
    "@ionic/storage": "1.1.6",
    "@ngtools/webpack": "1.1.9",
    "angularfire2": "^2.0.0-beta.6",
    "firebase": "^3.6.4",
    "ionic-angular": "2.0.0-rc.4",
    "ionic-native": "2.2.11",
    "ionicons": "3.0.0",
    "rxjs": "5.0.0-beta.12",
    "zone.js": "0.6.26"
  },
  "devDependencies": {
    "@ionic/app-scripts": "^1.1.0",
    "@ngtools/webpack": "^1.1.9",
    "@types/request": "0.0.30",
    "ionic-minify": "^2.0.10",
    "typescript": "2.0.9"
  },
  "cordovaPlugins": [
    "cordova-plugin-whitelist",
    "cordova-plugin-statusbar",
    "cordova-plugin-splashscreen",
    "cordova-plugin-device",
    "ionic-plugin-keyboard",
    "phonegap-plugin-push"
  ],
  "cordovaPlatforms": [],
  "description": "xxxxx: An Ionic project"
}

Do you see any issue with the dependencies or with the plugins?

The minimized main.js file is 5.8MB.

My app.module is:

import { NgModule, ErrorHandler } from '@angular/core';
import { IonicApp, IonicModule, IonicErrorHandler } from 'ionic-angular';
import { MyApp } from './app.component';
import { NextPayments } from './payment/nextPayments/nextPayments';
import { Login } from './user/login/login';
import { SignUp } from './user/signup/signup';
import { Terms } from './user/terms/terms';
import { Contactus } from './user/contactus/contactus';
import { ChangeEmail } from './user/changeEmail/changeEmail';
import { ChangePassword } from './user/changePassword/changePassword';
import { ResetPassword } from './user/resetPassword/resetPassword';
import { PaymentInformation } from     './payment/paymentInformation/paymentInformation';
import { UnidadesList } from './payment/unidadesList/unidadesList';
import { UnidadInformation } from     './payment/unidadInformation/unidadInformation';
import { PaymentConfirmation } from './payment/paymentConfirmation/paymentConfirmation';
import { PaymentHistory } from './payment/paymentHistory/paymentHistory';
import { OneClickPayment } from './payment/oneClickPayment/oneClickPayment';
import { HistoryInformation } from './payment/historyInformation/historyInformation';
import { AddPayment } from './payment/addPayment/addPayment';
import { AccountList } from './account/accountList/accountList';
import { AddAccount } from './account/addAccount/addAccount';
import { AccountInformation } from './account/accountInformation/accountInformation';
import { EqualValidator } from './directives/equalValidator';
import { AngularFireModule } from 'angularfire2';
import { CloudSettings, CloudModule } from '@ionic/cloud-angular';

export const firebaseConfig = {
    apiKey: "xxxxxx",
    authDomain: "xxxxxxxx",
    databaseURL: "xxxxxxxxxx",
    storageBucket: "xxxxxxxx",
    messagingSenderId: "xxx"
}

const cloudSettings: CloudSettings = {
  'core': {
    'app_id': 'xxxxx'
  },
  'push': {
    'sender_id': 'xxxxx',
    'pluginConfig': {
      'ios': {
        'badge': true,
        'sound': true
      },
      'android': {
        'iconColor': '#921F67'
      }
    }
  }
};

@NgModule({
  declarations: [
    MyApp,
    NextPayments,
    PaymentInformation,
    Login,
    PaymentConfirmation,
    AddPayment,
    EqualValidator,
    AccountList,
    AddAccount,
    HistoryInformation,
    Terms,
    Contactus,
    PaymentHistory,
    AccountInformation,
    UnidadInformation,
    UnidadesList,
    SignUp,
    ResetPassword,
    OneClickPayment,
    ChangeEmail,
    ChangePassword
  ],
  imports: [
    IonicModule.forRoot(MyApp, {
      monthNames: ['Enero', 'Febrero', 'Marzo', 'Abril', 'Mayo', 'Junio', 'Julio', 'Agosto', 'Septiembre', 'Octubre', 'Noviembre', 'Diciembre' ],
      monthShortNames: ['Ene', 'Feb', 'Mar', 'Abr', 'May', 'Jun', 'Jul', 'Ago', 'Sep', 'Oct', 'Nov', 'Dic' ],
      dayNames: ['Domingo', 'Lunes', 'Martes', 'Miércoles', 'Jueves',     'Viernes', 'Sabado' ],
      dayShortNames: ['Dom', 'Lun', 'Mar', 'Mie', 'Jue', 'Vie', 'Sab' ],
    }),
    AngularFireModule.initializeApp(firebaseConfig),
    CloudModule.forRoot(cloudSettings)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    NextPayments,
    PaymentInformation,
    Login,
    UnidadInformation,
    UnidadesList,
    PaymentConfirmation,
    AddPayment,
    Terms,
    Contactus,
    AccountList,
    AddAccount,
    AccountInformation,
    HistoryInformation,
    PaymentHistory,
    OneClickPayment,
    SignUp,
    ResetPassword,
    ChangeEmail,
    ChangePassword
  ],
  providers: [{provide: ErrorHandler, useClass: IonicErrorHandler}]
})
export class AppModule {}

And my app.components:

import { Component, ViewChild } from '@angular/core';
import { Nav, Platform, AlertController, IonicApp, ToastController,     MenuController } from 'ionic-angular';
import { StatusBar, Splashscreen } from 'ionic-native';

import { NextPayments } from './payment/nextPayments/nextPayments';
import { UnidadesList } from './payment/unidadesList/unidadesList';
import { PaymentHistory } from './payment/paymentHistory/paymentHistory';
import { PaymentInformation } from './payment/paymentInformation/paymentInformation';
import { Login } from './user/login/login';
import { ChangeEmail } from './user/changeEmail/changeEmail';
import { OneClickPayment } from './payment/oneClickPayment/oneClickPayment';
import { ChangePassword } from './user/changePassword/changePassword';
import { Contactus } from './user/contactus/contactus';
import { Terms } from './user/terms/terms';
import { Response } from './models/response';
import { Payment } from './models/payment';
import { Session } from './session/session';
import { Push, PushToken } from '@ionic/cloud-angular';
import { AccountList } from './account/accountList/accountList';
import { UserService } from '../app/user/userService';
import { ServerService } from './server/server.service';
import { LoadingController } from 'ionic-angular';
import { AccountService } from './account/accountService';
import { PaymentService } from './payment/paymentService';

declare var navigator: any;

@Component({
  templateUrl: 'app.html',
  providers: [Session, UserService, ServerService, PaymentService, AccountService]
})
export class MyApp {
  @ViewChild(Nav) nav: Nav;
  payment : Payment = new Payment();
  rootPage: any = Login;
  backButtonPressed: boolean = false;
  pages: Array<{title: string, component: any}>;

  constructor(public loadingCtrl : LoadingController, public paymentService     : PaymentService, public accountService : AccountService, public menuCtrl: MenuController, public toastCtrl: ToastController, private ionicApp : IonicApp, public platform: Platform, public serverService: ServerService, public session: Session, public push: Push, public userService: UserService, public alertCtrl: AlertController) {
    this.initializeApp();
    if(this.session.isAuth())
      this.rootPage = NextPayments;
    // used for an example of ngFor and navigation
    this.pages = [
      { title: 'Próximos Pagos', component: NextPayments },
      { title: 'Mis Unidades', component: UnidadesList },
      { title: 'Mis C.B.U.', component: AccountList },
      { title: 'Historial de Pagos', component: PaymentHistory },
      { title: 'Cambiar Email', component: ChangeEmail },
  { title: 'Cambiar Contraseña', component: ChangePassword },
  { title: 'Términos y Condiciones', component: Terms },
  { title: 'Contáctenos', component: Contactus },
  // { title: 'Configuración', component: Settings }
];

this.push.rx.notification()
    .subscribe((msg) => {
      let loader = this.loadingCtrl.create({
        content: "Obteniendo información..."
      });
      loader.present();
      if(msg.payload != undefined && msg.payload != null){
        let payload : any = msg.payload;
        if(payload.id != ""){

              this.paymentService.getPayments(payload.id).then((result : Response) => {
                if(result.success){
                  if(result.eror!= null && result.eror == "id invalido"){
                    this.session.clearSession();
                    this.nav.setRoot(Login);
                  }
                  else{
                    if(result.data!= null && result.data.expensas.length > 0){
                        this.payment = result.data.expensas[0];
                        this.payment.date = this.payment.diahabil;
                        if(this.payment.diahabil > this.payment.date1 && this.payment.date2.toString() != "0000-00-00")
                          this.payment.suggested = this.payment.importe2;
                        else
                          this.payment.suggested = this.payment.importe1;
                        this.accountService.getAccounts().then((result : Response) => {
                          if(result.success){
                            if(result.data.accounts != null && result.data.accounts.length > 0){
                              loader.dismiss();
                              this.payment.account = result.data.accounts[0];
                              this.nav.setRoot(OneClickPayment, {
                                item : this.payment
                              });
                            }
                            else{
                              loader.dismiss();
                              this.payment.account = result.data.accounts[0];
                              this.nav.setRoot(PaymentInformation, {
                                item : this.payment
                              });
                            }
                          }
                        });
                    }
                  }
                }
              });
        }
      }
      loader.dismiss();
      this.nav.setRoot(NextPayments);
        });
  }

  readPushNotification(){
      this.push.register().then((t: PushToken) => {
        return this.push.saveToken(t);
      }).then((t: PushToken) => {
        this.session.setPnToken(t.token);
      });
  }

  registerBackButtonAction() {
    this.platform.registerBackButtonAction(() => {
      let activePortal = this.ionicApp._modalPortal.getActive();
      if (activePortal) {
        activePortal.dismiss().catch(() => {});
    activePortal.onDidDismiss(() => {});
    return;
  }
  if(this.menuCtrl.isOpen()){
    this.menuCtrl.close();
  }
  else{
    let view = this.nav.getActive();
    if(view.component.name == "NextPayments" || view.component.name == "Login")
      this.showExit();
    else
          return view._nav.canGoBack() ? view._nav.pop() :         this.goBacktoDefaultPage();
        }
    }, 1);
  }

    goBacktoDefaultPage(){
      if(this.session.isAuth())
        this.nav.setRoot(NextPayments);
    }
   showExit() {
     if (this.backButtonPressed) {
       this.platform.exitApp();
     } else {
       this.toastCtrl.create({
         message: 'Presione nuevamente para cerrar la aplicación.',
         duration: 2000,
         position: 'top'
       }).present();
       this.backButtonPressed = true;
       setTimeout(() => this.backButtonPressed = false, 2000);
     }
   }

  initializeApp() {
      this.platform.ready().then(() => {
      // Okay, so the platform is ready and our plugins are available.
      // Here you can do any higher level native things you might need.
      StatusBar.styleDefault();
      Splashscreen.hide();
      this.registerBackButtonAction();
      this.readPushNotification();
    });
    if(navigator['connection']['type'] == "none"){
        let alert = this.alertCtrl.create({
          subTitle: "No posee conexion a internet. La aplicación se cerrara. Por favor reintente cuando posea conectividad.",
      buttons: [
        {
        text: 'Aceptar',
        handler: () => {
          this.platform.exitApp();
        }
      }
      ]
    });
        alert.present();
    }
  }

  openPage(page : any) {
    // Reset the content nav to have just this page
    // we wouldn't want the back button to show in this scenario
    this.nav.setRoot(page.component);
  }

  logout(){
    this.session.clearSession();
    this.userService.setToken(null);
    //UNREGISTER PUSH NOTIFICATION TOKEN
    this.push.unregister();

    this.nav.setRoot(Login);
  }
}

Any suggestion? do you need more information? It's my first app in Ionic2 and taking 15 seconds to load is not acceptable. Please help to find a solution, I invest a lot of time in this app.


EDIT: package.json updated:

"@angular/animations": "^4.0.0",
"@angular/common": "4.0.0",
"@angular/compiler": "4.0.0",
"@angular/compiler-cli": "4.0.0",
"@angular/core": "4.0.0",
"@angular/forms": "4.0.0",
"@angular/http": "4.0.0",
"@angular/platform-browser": "4.0.0",
"@angular/platform-browser-dynamic": "4.0.0",
"@angular/platform-server": "4.0.0",
"@ionic-native/core": "3.4.2",
"@ionic-native/push": "^3.4.4",
"@ionic-native/splash-screen": "3.4.2",
"@ionic-native/status-bar": "3.4.2",
"@ionic/cloud-angular": "^0.12.0",
"@ionic/storage": "2.0.1",
"@ngtools/webpack": "1.3.0",
"angularfire2": "^2.0.0-beta.8",
"firebase": "3.7.8",
"ionic-angular": "3.0.1",
"ionicons": "3.0.0",
"rxjs": "5.1.1",
"sw-toolbox": "3.4.0",
"zone.js": "^0.8.4"
Faabass
  • 1,394
  • 8
  • 29
  • 58
  • I am also facing same issue.Wait for ionic team to release newer optimized versions.They are working on it. – Yogeshwar Tanwar Apr 13 '17 at 05:13
  • Do you have a link with more information? Anyway, there are several pages with suggestions (which didn't work for me) but maybe is an issue from ionic 2.2.1? Did you try a lower version? – Faabass Apr 13 '17 at 06:00

5 Answers5

1

Try crosswalk or crosswalk lite and see how the performance is.The APK size will increase by 15-30 MB depending on the crosswalk you're using,but you can expect a uniform performance throughout different devices.

Naveen
  • 163
  • 3
  • 11
  • But I don't have issues with the performance in different devices, the performance is always very slow when the app is loading. Then everything is ok. Will this help to the app loading time? – Faabass Apr 13 '17 at 17:52
  • I tried crosswalk but there wasn't much difference between the crosswalk and chromium startup time.The animations are better in crosswalk though.The app I'm working is on the same profile as yours and the startup time is around 6-9 seconds(APK-4.7MB).I'm using Ionic 2.3 and Ionic native 3.x though the startup was same before I updated to latest ones. – Naveen Apr 14 '17 at 05:27
0

Try to update your app... 2.0.0-rc.4 use a really out of date version of Ionic and Angular.

You can find more info here: changelog Ionic2

I'm working on a big app with a lot of plugins and images, and with ionic run android --prod, app is taking like 3-4 seconds to start in a real device (Galaxy S4 - relatively old).

Is a tedious job, but sooner or later you will have to do it... A lot of new features have been added too!

That's my package.json, to give you an idea:

  "dependencies": {
    "@angular/animations": "4.0.1",
    "@angular/common": "4.0.1",
    "@angular/compiler": "4.0.1",
    "@angular/compiler-cli": "4.0.1",
    "@angular/core": "4.0.1",
    "@angular/forms": "4.0.1",
    "@angular/http": "4.0.1",
    "@angular/platform-browser": "4.0.1",
    "@angular/platform-browser-dynamic": "4.0.1",
    "@ionic-native/barcode-scanner": "3.4.4",
    "@ionic-native/camera": "3.4.4",
    "@ionic-native/core": "3.4.4",
    "@ionic-native/facebook": "3.4.4",
    "@ionic-native/google-plus": "3.4.4",
    "@ionic-native/network": "3.4.4",
    "@ionic-native/social-sharing": "3.4.4",
    "@ionic-native/splash-screen": "3.4.4",
    "@ionic-native/sqlite": "3.4.4",
    "@ionic-native/status-bar": "3.4.4",
    "ionic-angular": "3.0.0",
    "ionicons": "3.0.0",
    "jsbarcode": "3.5.9",
    "moment": "2.18.1",
    "rxjs": "5.3.0",
    "sw-toolbox": "3.6.0",
    "zone.js": "0.8.5"
  },
  "devDependencies": {
    "@ionic/app-scripts": "1.3.0",
    "typescript": "2.2.2"
  }

Best solution maybe will be starting a new project and add your plugin/src code. With Ionic 2 v3.0.1 (2017-04-06) app starts is really fast in production mode.

I hope to have been a help to you. :)

mosca90
  • 999
  • 10
  • 19
  • Thanks! I created a new app with the latest version and migrate all the logic but I get the same result. Please check my app.components.ts to see if there is anything weird there... please note initializeApp() methid. Is ok to register the push notification as soon as the app start? Also, it's ok to put everything on declarations and entryComponents in app.module.ts? – Faabass Apr 17 '17 at 04:21
  • I notice that the app is calling to https://api.ionic.io/insights as soon as it start.. is that ok? I tested an empty project and it load in 3/4 seconds, but mine is not so complex or big, so it should be moreless the same. Any clue? – Faabass Apr 17 '17 at 04:24
  • Maybe try to remove some functionality 1 by 1 and prevent it from being initialized and check if start time decrease.. So maybe you can find out what specific feature increase startup time and then we can try to find a solution! **initializeApp()** seems ok, and what is `api.ionic.io/insights`? – mosca90 Apr 18 '17 at 09:04
0

use lazy loading of pages instead of declaring all pages in the app.module.ts. In app.component.ts declare the root page as string instead of any rootPage: String = HomePage. Also while declaring the pages for navigation just declare as this.navigation.push("secondPage"). we don't need to import the page for navigation purposes..

Santosh Kumar
  • 77
  • 2
  • 8
0

Check to see if Firebase is causing the slow loading. Some users (myself included) are currently experiencing a similar issue. Here is a discussion with some tips: https://forum.ionicframework.com/t/ionic-3-super-slow-with-firebase-on-device-emulator/87233/50

Scott Winn
  • 31
  • 4
0

consider minifying your code using js minifier of your choice, I prefer uglify and use it via gulp task runner

first install gulp-cli via npm globally, and then install gulp in the dev folder and then all needed gulp plugins(gulp-useref, gulp-uglify, gulp-if), then in the index.html file surround all js references by comments that will be used by useref to combine all js files in one file and replace their references by one reference

<!--build:js build/all.js -->

<script src="build/vendor.js"></script>
<script src="build/main.js"></script>

<!-- endbuild -->

then create a gulpfile.js in the development folder

var gulp = require("gulp");
var uglify = require("gulp-uglify");
var useref = require("gulp-useref");
var gulpIf = require("gulp-if");


gulp.task('build', function () {

    gulp.src('www/index.html')
        .pipe(useref())
        .pipe(gulpIf('*.js', uglify()))
        .pipe(gulp.dest('www'));

});

then open cmd in the dev folder and run gulp build the js files will be combined and minified and the reference in the index.html will be updated accordingly

you can also use use del plugin to delete unnecessary files

Edit

passing the --prod flag to the build command makes use of Ahead-of-Time compilation that uglifies the js files prior to building the package

Mohamed Ali
  • 3,717
  • 1
  • 33
  • 39