[SOLVED] App need authentication, speed up boot time with dummy page?

Hey,

  • Notice:

This post most probably only apply on app where an authentication is mandatory

  • Summary:

I just add an idea, implemented it and it seems that I gained 200-300ms seconds (7.5%) on my boot time.

  • Question:

Look quite promising but I wanted to share it to know if you think guys, that it could be a good idea or if you see any risks of doing following this implementation aka is that a bad idea?

  • Background:

I’ve got an app where the login is mandatory. First time user have to log in, then with token automatic login.

If I’m not wrong the most classical way to solve that is to implement a LoginPage. If user log for the first time, the page is displayed till user process what he has to do (clicks). On next app starts, if token is used, same page is displayed with a spinner while in the background the login is automatically is processed.

  • Problem:

In app.component, the element “rootPage” is, again if I’m not wrong, mandatory. So the most classical way to achieve the above process is to set then the “rootPage=LoginPage” even if on automatic login, the LoginPage wouldn’t be really needed. Means that even when an automatic login as to be performed, the LoginPage still gonna be rendered (right?)

  • Idea

But today I noticed that, even my LoginPage just render a spinner while doing the automatic login, it still took a bit of time to be processed (from ionViewDidLoad to ionViewDidEnter or ionViewDidLeave) because even if I only display a spinner, there is still some work to do to not render the rest of the page (like in my case, which you probably have to, my login page contains a slider to display informations about the app).

Ultimately, I thought that, that time could be saved in case of an automatic login, so I just created a DummyPage empty which I set in app.component as root (rootPage=DummyPage).

The DummyPage takes now care to process the login status. If new or token expired, this DummyPage set then the root to the login page, else the DummyPage process an automatic login and set then the next page as root.

  • Gui

Of course, to make a not to ugly login, I let the DummyPage be renderer behind the splash screen, therefore the user never (or should never) see it (here I’m not 100% sure…)

  • Results

As a result, I could notice that I save around 200-300ms (7.5% of my overall boot time) which in my point of view, is a good quick small win.

So again, anyone see a risk in that implementation?

Hmmm had a similar situation, I basicly turned off the automatic splashscreen hiding.

So when a user opens the app, the splashsreen shows, upon platform ready the app checks the login status, in case the token is valid set the rootPage to homepage else set the rootPage to login. When its done, hide the splashscreen.

It inscreases the app load time by the amount of time needed for login.

Thx for the feedback. So during the time the app checks the login status, rootPage is just not set right?

Actually, I just now unset the root page, and it works better than defaulting it to loginPage. :slight_smile: hahah thanks!

Ye I was setting the rootPage to loginPage. And when the app starts it would check the login status and then change the root page to either home or login depending on the status.

But this all was hidden by manualy controlling the splashscreen.

1 Like

Haha awesome :wink: I should try your solution too, maybe I could spare some more ms in that way too…gonna first have some tests round on the new implementation.

You could inject a service into app.component.ts that tests local login status and then set the value of this.rootPage appropriately. Whether it would take more or less time than your current setup I don’t know. If you compare the two approaches I’d be interested in what you discover.

1 Like

Good idea, even I’m not sure I gonna try that now right know, because the refactoring time would take a little bit more than a couple of minutes :wink:

For my understanding, you would do that, check the status and then set the rootPage, in the app.component constructor or in afterViewInit?

I haven’t experimented, so I don’t know all the possibilities. But I’ve tested in the first line of the app.component.ts constructor, before platform ready. (Inside platform ready I got a white screen.)

1 Like

Oki doki thx for the feedback!

FWIW, I handle this by having a service that exposes an authentication state notifier. In my app component’s constructor I subscribe to it and conditionally set the root page to the dashboard (if the authenticator emitted true) or login (if false). This gives me app-wide logout functionality for free.

If you are storing your credentials in ionic-storage, you must wait for it to be ready (which in turn will wait for the platform, so I’m confused about @AaronSterling’s WSOD - that doesn’t happen to me and I’m effectively waiting for platform.ready). Finally, if you’re using lazy page loading, rootPage can be a string.

1 Like

Ok, I’m still getting a whitescreen, with the following code.

platform.ready().then(() => {
      // it works if I set this.rootPage on this line
      this.credListener.validCredentialsInStorage()
          .then(bool => { console.log('bool',bool);
                          if (bool) {this.rootPage = HomePage}
                          else if (!bool) {this.rootPage = LoginPage};
                          console.log('rootpage',this.rootPage);
                        });

bool displays correctly (true or false depending on whether there are credentials in Ionic Storage). rootPage displays correcty (as a function to the desired page). But inside the Promise (as shown) I get a white screen, while if I set the root page where the commented line is, it works fine. Both HomePage and LoginPage have factories. Do you know what I’m missing?

Hmm. This seems tough to investigate without a complete minimal reproduction repo. Could you throw one together?

I ought to talk to someone else before leaving the impression that I’m sharing any code, innocent as it might be in reality. If I don’t follow up, thanks for being willing to take a look.

Well, if that doesn’t work out, maybe I can distill what I have as a working example and you can try to work backwards from how yours differs.

This works. In app.html:
<ion-nav #rootNav [root]="rootPage"></ion-nav>

In app.component.ts:

import { ViewChild } from '@angular/core';
import { Nav } from 'ionic-angular';

@Component({
  templateUrl: 'app.html',
})
export class MyApp {
  @ViewChild('rootNav') nav: Nav;

ngAfterViewInit() {
    this.credListener.validCredentialsInStorage()
          .then(bool => { 
                          if (bool) {this.nav.push(HomePage)}
                          else if (!bool) {this.nav.push(LoginPage)};
                        });
  }

@rapropos thx for the comment. really interesting specially the part about the waiting time of ionic-storage to be ready. I have to try your architecture because it might makes me gain some more ms…btw if you’re not against distilling some code I would not be against it :wink:

@rapropos I think I’m not gonna need some code, I achieved to do it :wink:

I finally ended up making a Star Lord solution (“a bit of both”).

I create a service to expose an authentication state notifier but I combined it with the last solution found by @AaronSterling here above (I can’t really set the rootPage conditionally, would be a crazy refactoring, I’ve got like 5 root conditional pages + deep linking etc. and I don’t want to duplicate too much my code).

So, look finally like following:

  import { ViewChild } from '@angular/core';
  import { Nav } from 'ionic-angular';
  
  @Component({
    templateUrl: 'app.html',
  })
  export class MyApp {
    @ViewChild('rootNav') nav: Nav;
    // here no rootPage = ... even no where that kind of code
  
   private authenticationSubscription: Subscription;

   constructor(...) {
          
        // 1. Subscribe to the state
        this.authenticationSubscription = this.authenticationService.watchLoginState().subscribe((loginState: LoginState) => {
          // LoginState contains the user info I need and the state itself
          this.navToRoot(loginState);
        });

        // 2. When ready process to check if automatic login or login is needed
       // In that service I gonna query ionic-storage
       platform.ready().then(() => {
            this.authenticationService.initLoginState();
       });
   }
  
   private navToRoot(loginState: LoginState) {
        // For example, I do more stuffs here
       if (loginState.state === 'granted') {
           this.app.getRootNav().setRoot(FirstPage);
       } else {
           this.app.getRootNav().setRoot(LoginPage);
       }
   }
 
   ngOnDestroy() : void {
       if (this.authenticationSubscription != null) {
        this.authenticationSubscription.unsubscribe();
    }
   }
  }

I’ve got now a question, to you guys or maybe someone from Ionic: is it safe to not set “rootPage=SomePage;”?

It look like it’s working like a charm but do that still gonna work in the future?

@AaronSterling about the two approaches, or at least a comparison with I’ve got and the last one, I’ve to say there isn’t a crazy improvements, but, the new approach gave way more stable results!

With previous approach, my Login lasted most of the time 3.7 sec but still reached sometimes 4.1 sec

With the new approach, it seems that I constantly reach 3.7 sec

And finally in comparison to my solution with a dummy page or even a solution with a login page as rootPage, when the first root page is 100% conditionally, the splash screen could be dismissed faster.

In a case where I’ve got for example:

app.component -> dummy page -> real first page

I’ve to dismiss the splash screen on ionViewDidEnter of the first page to avoid displaying the transition to the user

But with a flow like

app.component -> real first page

I could dismiss the splash screen in ionViewDidLoad() of the first page

Result: around 200-300ms saved more, my boot time is around 3.4 sec now. Still a bit of work to my goal of 2sec, but that step forward makes me happy :slight_smile:

I close this issue and set the solution of @AaronSterling as the solution coz it’s the one I finally implemented and because it’s faster that having a dummy page