Ionic 2 : Issues and Challenges

In my last blog we have seen the key benefits of Ionic 2. It includes speedup factor, organized directory structure, easy navigation, generator commands, set of native API and support for cross platform.

However, if you are thinking of migrating from Ionic 1 to Ionic 2, you may face different challenges or issues. You may either find ready solutions to these or you may have to implement solution yourself. I have successfully upgraded my project and hence would like to share my experience, with the issues I faced, and the way I solved these. Hope it will help. Lets see the issues one by one :

Handle Hardware Back Button

Many times we stuck at particular problem, trying to find solution. But unfortunately we do not get anything. Same thing happened with me. I was trying to handle hardware back button manually with the help of method provided by Ionic 2 :

    this.platform.registerBackButtonAction((event) => {
     if(this.navCtrl.canGoBack()){
       this.navCtrl.pop();
     }
   }, 100);
  

But the problem was, whenever I press back-button for consequently two times, it was popping root page too. This should not happen. More over this was very annoying to the users. I tried with many options. But finally this issue is handled in updated version of Ionic 2 i.e RC5

The point is, whenever we failed to find any solution, check for updated versions of packages we are using and confirm if the issue is handled in updated version. If not, there is no other way but to fix it yourself & send a PR.

Camera opening issue in Android Version 7 (Nougat)

In my app, on a page I was taking image as a input from user. There are two options, choose image from gallery or click a picture using the camera. Everything was working perfectly. But when Nougat was released I did a test pass to ensure that nothing is broken. But to my surprise, the camera was not working. Then I checked for issues in plugin on git. I found one issue related to it was raised and also fixed in updated version of ‘cordova-plugin-camera’. So I did update my plugin version and everything started working.

So, before using any plugin, first check for the issues listed. If any of the issues is a concern, look for alternatives. Else go ahead and use the plugin. (NOTE: In my experience the cordova & ionic community is very active & helpful. The issues are usually addressed pretty quickly. So you may take that chance too, as I did ;-))

Change is payment plugin usage in Ionic 2

The payment gateway I am using is Razor-pay. I had already used Razor pay plugin in the Ionic 1 build and naturally took it forward to Ionic 2. I implemented the integration in the same way as in Ionic 1. But the plugin did not work.  After spending some time investigating I decided to contact the Razor-pay tech support team. They responded quickly and told me the way to use it in Ionic 2 and its working now. Thanks to them!

If you stuck with a problem in any library, package or plugin and do not find any demo example, then I would highly recommend contacting the contributors. They will surely help!!

Check my upcoming blog for details on how to do 🙂

Issue of opening downloaded file in Nougat

In my app, I was showing list of files, having type PDF and image. This was working earlier but then suddenly users started reporting that the file is not opening. I tried and could reproduce the issue. The file was getting downloaded in app storage but not opening. The error I was  getting was “Promise unresolved”. I had already upgraded to Nougat, but did not think that was the cause. And kept thinking that it was a regression bug. However, after testing on many android versions, I came to know that it is an issue with Android 7.

I checked File-Opener plugin to verify if its having issue with Android 7 and there it was. The File-Opener plugin team fixed that issue in newer version(2.0.7). I did update my app with new plugin version. But unfortunately I got different error after update. The error was,

“android.os.FileUriExposedException: file:///storage/emulated/0/test.txt exposed beyond app through Intent.getData()”.

This was wired. But then after some digging I figured out the solution. This is how it goes – whenever we build the app, the latest installed SDK version is referred. I was facing this error because my app was build with SDK 24. The solution to resolve the exception above is to change android:targetSdkVersion to 23 in AndroidManifest.xml. Essentially, downgrade. This is required because, SDK 24 only supports the URI format as content:///… and not file://, and I my code was using file:// everywhere. A long term solution is to use the latest format, however, it depends on how much time you have. (Note: You can Google for “Nougat file URI” and you will find descriptive articles about this issue)

  # File path = '<app_name>/platforms/android/AndroidManifest.xml'

  <uses-sdk android:minSdkVersion="16" android:targetSdkVersion="23" />

After updating package, got lots of errors while building app

I updated my Ionic version to RC5. Before update everything was working good. After update, for the sake of testing, I started running app with ‘ionic run android’. I got hundreds of various @typing errors. I tried with different solutions including re-installation of package. But none of them succeeded. Finally I solved it with following steps :

1. Rename original project with different name
2. Clone new copy of it
3. Uninstall cordova and ionic globally
4. Install both again with latest version
5. Run ‘npm install’
6. Add platform as per requirement
7. Build app

Page pop not possible along with params

In Ionic 2, its not possible to pop page along with some data or params. Many times we need to transfer data back to source page after pop. In this case, I used events provided by Ionic CLI. The page from which I wanted to pop, was publishing event. And the page to whom I wanted to pass parameter, was registered for same event.

For example, suppose I have two pages named as home page and contact page. First I will go to home page, then contact page. Here I want to transfer some data from contact page to home page with pop operation. I need to import Events class from ionic-angular library. Then My home page should be subscribed to event like ,

    this.events.subscribe('contact:data', (data) => {
      console.log("Data got from contact page : ", data);
    });
  

Now in contact page, at the time of pop operation I will publish event (with data) of same name. So that while popping, event will be captured in home page along with data. Here contact page will publish event like:

    this.events.publish('contact:data', {contact_info: "9988776655"});
    this.navCtrl.pop();
  

Unable to build app

In between app development, newer version of typescript was available. So I thought, It will be helpful if I update version of typescript. So I did update. But while building app, I was not able to do it. The problem was my typescript version(2.0.3) was not compatible with ionic app-script version. So I installed compatible version of app-script, then it worked.

So, while updating any particular package version, first check for compatibility issues, then only update.

Adding storage support in app

We may require to store data within app, basically offline storage. The main purpose of storing data is apparent,  to optimize load time. Ionic 2 provides more convenient way for storage support. It gives SQLite ionic native class to access cordova-sqlite-storage. Through this class we can easily apply CRUD operations on database. Its more easier to have storage support in Ionic 2 than Ionic 1.

Check my next blog for details on how to do 🙂

Benefits of Ionic 2

Ionic is world’s most popular cross platform mobile development technology. Basically its hybrid mobile app development framework. Build on top of Cordova, which enables us to build app along with web technologies. The goal behind developing Ionic is to give web developers a way to use their skill-set to build mobile applications.

Recently Ionic 2 has been launched. Conceptually Ionic 2 is similar to Ionic 1. In Ionic 2 controller hold all logical part and view is handled by template, except controllers are classes. Like this there are many key differences. Ionic 2 is build on the base of Angular 2 which uses typescript. All controllers are written in .ts file. Hence while building a app, these files get converted into .js files. This is the process of ‘Transpiling’. Transpiling does not allow logic to be directly available through debugging.

Now a days Ionic 2 is top choice for fast development. There are some reasons why it is more preferable than Ionic 1. Followings are some key points why we should migrate from Ionic 1 Ionic 2 :

Speed :

In Angular 2 change detection in model is very quick. So, Ionic 2 app is faster than  Ionic 1.

Organized directory structure :

In Ionic 1, there is no standard way to organize our files. User can arrange file as per his/ her convenience. But Ionic 2 comes with its own directory structure. Every page is referred as component. Each component comes with its own folder. It contains .ts file as class/ controller, .css file and .html file as a view. For e.g. suppose we have two pages as home and about. Then structure be like :

Ionic 1 :

  • /www
    • /js
      • home.js
      • about.js
    • /templates
      • home.html
      • about.html
    • /css
      • home.css
      • about.css

Ionic 2 :

  • Home
    • home.ts
    • home.html
    • home.css
  • About
    • about.ts
    • about.html
    • about.css

Navigation :

In Ionic 1, navigation is done by routing through states. But in Ionic 2, more easier approach is used that is ‘stack’. When we want to redirect to particular page, we will just push that page onto navigation stack. We can come back to previous page by popping the current page from stack. As simple as that. Lets see difference between Ionic 1 and Ionic 2 navigation :

Ionic 1 : We can specify routes like this,

  $stateProvider
   .state('home', {
     url: '/home',
     templteUrl: 'templates/home/index.html',
     controller: 'HomeController'
   })
   .state('about', {
     url: '/about',
     templateUrl: 'templates/about/index.html',
     controller: 'AboutController'
   });

Whenever we want to go from home state to about state we just give,

  $state.go('about');

Ionic 2 : Similarly, suppose we have home page as,

  import { Component } from '@angular/core';
  import { NavController } from 'ionic-angular';
  import { About } from '../about/about';

  @Component({
    selector: 'page-home',
    templateUrl: 'home.html'
  })
  export class Home {
    constructor(public navCtrl: NavController){}
    loadAbout(){
     // load about page
    }
  }

To go to about page, we just push page onto navigation stack,

  loadAbout(){
    this.navCtrl.push(About);
  }

To remove page from stack or to go to previous page,

  this.navCtrl.pop();

Generators :

In Ionic 1, whenever we need to add new controller, we just define it in some file. Then associate controller with relative template file with help of state-provider. This process is very simple in Ionic 2. With Ionic 2 CLI, we can easily generate pages, providers, pipes, etc. Ionic 2 provides generator command for it. Lets have a look,

1. Pages :

These are main component of app. When we create new page, it comes with 3 files as mentioned above. To generate page command is :

  ionic generate page Home or ionic g page Home

The page comes with default structure. Its looks like :

  import { Component } from '@angular/core';
  import { NavController } from 'ionic-angular';

  @Component({
    selector: 'page-home',
    templateUrl: 'home.html'
  })
  export class HomePage {

    constructor(public navCtrl: NavController) {}

    ionViewDidLoad() {
      console.log('Hello HomePage Page');
    }

  }

2. Provider:

Providers are similar to service in Ionic 1. Every provider is injectable. Means we can import or inject service, provided by provider. The command to generate providers is :

  ionic g provider ApiServiceProvider

The default structure of provider is :

  import { Injectable } from '@angular/core';
  import { Http } from '@angular/http';
  import 'rxjs/add/operator/map';

  @Injectable()
  export class ApiServiceProvider {

    constructor(public http: Http) {
      console.log('Hello ApiServiceProvider Provider');
    }

  }

3. Pipe:

Pipe is one of the decorator. The main goal of pipe is to transform the given set of values. Pipe is also injectable. The default method in each pipe class is ‘transform’. Our input transformation logic comes here. The command to generate Pipe :

  ionic g pipe Lowercase

The default structure of pipe is :

  import { Injectable, Pipe } from '@angular/core';

  @Pipe({
    name: 'lower'
  })
  @Injectable()
  export class LowerCase {
    transform(value, args) {
      value = value + ''; // make sure it's a string
      return value.toLowerCase();
    }
  }

We can use this pipe in template as,

  <label>{{name | lower}}</label>

Set of API :

To build dynamic app, we may need various cordova plugins. In Ionic 1, when we use any plugin we need to inject related cordova service in relavant controller. Then only we can access plugin feature. For example, suppose we want to use cordova plugin to access contact from mobile. For it we will install plugin ‘cordova-plugin-contacts’. Once done, we can use it like this in Ionic 1:

  angular.module("app")
    .controller('ContactController', function($scope, $cordovaContacts, $cordovaToast){
      $scope.findContact = function(){
        Contacts.find(['*'], {filter  : "TPN whatsapp number"}).then(function(contactFound){
           if(contactFound.length >= 1){
             $cordovaToast.showShortBottom('Contact Found!!!');
           }
        });
      }
    })

This scenario looks clean in Ionic 2. It provides large set of Native API classes. Using these classes, we can easily use any  plugin with app. To integrate contact plugin, Ionic 2 provides native class names as ‘Contacts’. We can use it like this:

  import { Component } from '@angular/core';
  import { ToastController } from 'ionic-angular';
  import { Contacts } from 'ionic-native';

  @Component({
    selector: 'page-home',
    templateUrl: 'home.html'
  })
  export class Home {
    constructor(public toastCtrl: ToastController){}
    findContact(){
      Contacts.find(['*'], {filter  : "Support Contact Number"}).then((contactFound) => {
        if(contactFound.length >= 1){
          let toast = this.toastCtrl.create({
            message: "Contact Found!!!",
            duration: 2000,
            position: 'bottom'
          });
          toast.present();
        }
      });
    }
  }

Support for cross-platform :

Ionic 1 comes with support to only 2 platforms, i.e. Android and IOS. Ionic 2 allows us to build app which is compatible with Android, IOS as well as Windows phone.

In next blog we will see what major issue we can face while developing an app in Ionic 2 and solution to it.