Skip to main content

Recently a client handed me code that runs an app through iOS and Android.  No details about whether native or otherwise.  Once I had the opportunity to crawl through the code, definitely not native.  Typescript, Angular, Cordova... etc.

Glancing at the modification dates, the last time something had been tweaked on the app as June 2021.  Which immediately raises a flag that there are potentially a lot of issues with the code.  At this stage my concern wasn't with how the code had been written.  More the supporting packages would be out of date (absolutely) but importantly possibly deprecated.

Following are the steps that I took to get the app up and running locally.

 

Cordova Setup​

Additional setup is required for Cordova to support programmatic builds. This section is not necessary for Capacitor.

ios-sim & ios-deploy​

The ios-sim and ios-deploy are utilities that deploy apps to the iOS simulator and iOS devices during development. They can be installed globally with npm.

npm install -g ios-sim
brew install ios-deploy

 

Errors

Post executing the above commands to install iOS-sim and iOS-deploy, time to test an ionic command.  

Examples of ionic commands can be from the very simple ionic or running the info command...

ionic
ionic info

However, if I ran an ionic command, the response was:

"No command 'ionic' found"

So ionic hasn't been installed.  To install run

npm install -g cordova
npm install -g ionic

If I now execute the ionic command, the response is now:

   _             _
  (_) ___  _ __ (_) ___
  | |/ _ \| '_ \| |/ __|
  | | (_) | | | | | (__
  |_|\___/|_| |_|_|\___| CLI 6.19.0

  Usage:

    $ ionic <command> [<args>] [--help] [--verbose] [--quiet] [--no-interactive] [--no-color] [--confirm] [options]

  Global Commands:

    completion ...................... (experimental) Enables tab-completion for
                                      Ionic CLI commands.
    config <subcommand> ............. Manage CLI and project config values
                                      (subcommands: get, set, unset)
    deploy <subcommand> ............. (paid) Appflow Deploy functionality
                                      (subcommands: manifest)
    docs ............................ Open the Ionic documentation website
    info ............................ Print project, system, and environment
                                      information
    init ............................ (beta) Initialize existing projects with
                                      Ionic
    login ........................... Log in to Ionic
    logout .......................... Log out of Ionic
    signup .......................... Create an Ionic account
    ssh <subcommand> ................ Commands for configuring SSH keys
                                      (subcommands: add, delete, generate, list,
                                      setup, use)
    start ........................... Create a new project

  Project Commands:

    You are not in a project directory.

 

A step forwards!  Reading through the above comments, the last line caught my attention.  'You are not in a project directory'... I'm not in the correct directory.  Therefore, changing directories and the response is looking friendly.

Can I run the open ios command:

ionic capacitor open ios

On your first run you might have success and the command response is

> capacitor open ios

Success as the app opens in Xcode.  Instead I was greeted with an error.

 

Capacitor is it installed error

However, this was not the situation on my first run.  Instead the response

[WARN] Capacitor already exists in project.

       Since the Capacitor config already exists (./capacitor.config.json), the
       Capacitor integration has been enabled.

       You can re-integrate this project by doing the following:

       - Run ionic integrations disable capacitor
       - Remove the ./capacitor.config.json file
       - Run ionic integrations enable capacitor --add

[OK] Integration capacitor added!
[ERROR] Error while getting Capacitor CLI version. Is Capacitor installed?

 

Capacitor isn't installed.  Time to crawl through the package.json file and see what is happening!

How about attempting npm update?  No... I was meet with a wall of resistance.  So maybe time to try brute force.  First cross checking the lie of the land

npm outdated

Response

Package                             Current    Wanted    Latest  Location                                        Depended by
@angular-devkit/architect          0.1002.0  0.1002.1  0.1303.0  node_modules/@angular-devkit/architect          SAFS
@angular-devkit/build-angular      0.1002.0  0.1002.1    13.3.0  node_modules/@angular-devkit/build-angular      SAFS
@angular-devkit/core                  0.8.9     0.8.9    13.3.0  node_modules/@angular-devkit/core               SAFS
@angular-devkit/schematics            0.8.9     0.8.9    13.3.0  node_modules/@angular-devkit/schematics         SAFS
@angular/cli                         10.2.1    10.2.1    13.3.0  node_modules/@angular/cli                       SAFS
@angular/common                      10.2.2    10.2.5    13.3.0  node_modules/@angular/common                    SAFS
@angular/compiler                    10.2.5    10.2.5    13.3.0  node_modules/@angular/compiler                  SAFS
@angular/compiler-cli                10.2.5    10.2.5    13.3.0  node_modules/@angular/compiler-cli              SAFS
@angular/core                        10.2.5    10.2.5    13.3.0  node_modules/@angular/core                      SAFS
@angular/fire                         6.0.4     6.1.5     7.3.0  node_modules/@angular/fire                      SAFS
@angular/forms                       10.2.2    10.2.5    13.3.0  node_modules/@angular/forms                     SAFS
@angular/http                         7.1.4    7.2.16    7.2.16  node_modules/@angular/http                      SAFS
@angular/language-service            10.2.2    10.2.5    13.3.0  node_modules/@angular/language-service          SAFS
@angular/platform-browser            10.2.2    10.2.5    13.3.0  node_modules/@angular/platform-browser          SAFS
@angular/platform-browser-dynamic    10.2.2    10.2.5    13.3.0  node_modules/@angular/platform-browser-dynamic  SAFS
@angular/pwa                       0.1002.0  0.1002.1    13.3.0  node_modules/@angular/pwa                       SAFS
@angular/router                      10.2.2    10.2.5    13.3.0  node_modules/@angular/router                    SAFS
@angular/service-worker              10.2.2    10.2.5    13.3.0  node_modules/@angular/service-worker            SAFS
@asymmetrik/ngx-leaflet               5.0.2     5.0.2    13.0.2  node_modules/@asymmetrik/ngx-leaflet            SAFS
@capacitor/android                    1.5.3     1.5.3     3.4.3  node_modules/@capacitor/android                 SAFS
@capacitor/cli                        2.4.2     2.5.0     3.4.3  node_modules/@capacitor/cli                     SAFS
@capacitor/core                       1.5.3     1.5.3     3.4.3  node_modules/@capacitor/core                    SAFS
@capacitor/ios                        1.5.3     1.5.3     3.4.3  node_modules/@capacitor/ios                     SAFS
@ionic-native/core                    5.1.0     5.1.0    5.36.0  node_modules/@ionic-native/core                 SAFS
@ionic-native/http                   5.30.0    5.36.0    5.36.0  node_modules/@ionic-native/http                 SAFS
@ionic-native/splash-screen           5.1.0     5.1.0    5.36.0  node_modules/@ionic-native/splash-screen        SAFS
@ionic-native/status-bar             5.29.0    5.36.0    5.36.0  node_modules/@ionic-native/status-bar           SAFS
@ionic/angular                        5.4.1     5.9.3    6.0.13  node_modules/@ionic/angular                     SAFS
@ionic/angular-toolkit                2.3.3     2.3.3     6.1.0  node_modules/@ionic/angular-toolkit             SAFS
@ionic/lab                            3.2.9    3.2.11    3.2.11  node_modules/@ionic/lab                         SAFS
@ionic/storage                        2.3.1     2.3.1     3.0.6  node_modules/@ionic/storage                     SAFS
@types/jasmine                       2.8.19    2.8.19     4.0.0  node_modules/@types/jasmine                     SAFS
@types/node                        10.17.60  10.17.60   17.0.23  node_modules/@types/node                        SAFS
codelyzer                             4.5.0     4.5.0     6.0.2  node_modules/codelyzer                          SAFS
cordova-browser                       5.0.4     5.0.4     6.0.0  node_modules/cordova-browser                    SAFS
cordova-plugin-advanced-http          2.0.1     2.0.1     3.2.2  node_modules/cordova-plugin-advanced-http       SAFS
cordova-plugin-device                 2.0.2     2.0.2     2.0.3  node_modules/cordova-plugin-device              SAFS
cordova-plugin-ionic-webview          2.5.3     2.5.3     5.0.0  node_modules/cordova-plugin-ionic-webview       SAFS
cordova-plugin-splashscreen           5.0.2     5.0.2     6.0.0  node_modules/cordova-plugin-splashscreen        SAFS
cordova-plugin-statusbar              2.4.2     2.4.2     3.0.0  node_modules/cordova-plugin-statusbar           SAFS
cordova-plugin-whitelist              1.3.3     1.3.3     1.3.5  node_modules/cordova-plugin-whitelist           SAFS
cordova-sqlite-storage                5.1.0     5.1.0     6.0.0  node_modules/cordova-sqlite-storage             SAFS
core-js                              2.6.11    2.6.12    3.21.1  node_modules/core-js                            SAFS
firebase                              8.0.0    8.10.1    9.6.10  node_modules/firebase                           SAFS
jasmine-core                         2.99.1    2.99.1     4.0.1  node_modules/jasmine-core                       SAFS
jasmine-spec-reporter                 4.2.1     4.2.1     7.0.0  node_modules/jasmine-spec-reporter              SAFS
karma                                 5.2.3     5.2.3    6.3.17  node_modules/karma                              SAFS
karma-chrome-launcher                 2.2.0     2.2.0     3.1.1  node_modules/karma-chrome-launcher              SAFS
karma-coverage-istanbul-reporter      2.0.6     2.1.1     3.0.3  node_modules/karma-coverage-istanbul-reporter   SAFS
karma-jasmine                         1.1.2     1.1.2     4.0.1  node_modules/karma-jasmine                      SAFS
karma-jasmine-html-reporter           0.2.2     0.2.2     1.7.0  node_modules/karma-jasmine-html-reporter        SAFS
rxjs                                  6.6.3     6.6.3     7.5.5  node_modules/rxjs                               SAFS
ts-node                               7.0.1     7.0.1    10.7.0  node_modules/ts-node                            SAFS
tslib                                1.14.1    1.14.1     2.3.1  node_modules/tslib                              SAFS
tslint                               5.11.0    5.11.0     6.1.3  node_modules/tslint                             SAFS
typescript                            4.0.5     4.0.8     4.6.3  node_modules/typescript                         SAFS
zone.js                              0.10.3    0.10.3    0.11.5  node_modules/zone.js                            SAFS

For a slightly different presentation of the list, use the command

npx npm-check-updates -u

Ok still heading nowhere, time to try brute force

npm install --force

Most packages have been updated. So what happens when I run update command:

npm update

Errors remain.  So what is causing the errors now?

npm outdated
Package        Current  Wanted  Latest  Location                    Depended by
@angular/http    7.1.4  7.2.16  7.2.16  node_modules/@angular/http  SAFS
tslint          5.20.1  5.20.1   6.1.3  node_modules/tslint         SAFS

Researching each of the packages listed above, only to discover that both are now deprecated.  THis is where the real issues begin to raise their head.  What is the impact of changing these packages?

@angular/http - use instead @angular/common

npm i -D tslint-to-eslint-config
npm i -D eslint

 

Capacitor already exists in project error

When running tests on other app packages, rather than is it installed error I would be welcomed by a subprocess error.  Where the response is

ionic capacitor open ios
> ionic integrations enable capacitor

[WARN] Capacitor already exists in project.

       Since the Capacitor config already exists (./capacitor.config.json), the
       Capacitor integration has been enabled.

       You can re-integrate this project by doing the following:

       - Run ionic integrations disable capacitor
       - Remove the ./capacitor.config.json file
       - Run ionic integrations enable capacitor --add

[OK] Integration capacitor added!
> capacitor add ios
[capacitor] [error] Capacitor could not find the web assets directory "/Users/andrewfletcher/Apps/nov-FRDC/SAFS/www".
[capacitor]     Please create it and make sure it has an index.html file. You can change
[capacitor]     the path of this directory in capacitor.config.json (webDir option).
[capacitor]     You may need to compile the web assets for your app (typically 'npm run build').
[capacitor]     More info: https://capacitorjs.com/docs/basics/building-your-app
[ERROR] An error occurred while running subprocess capacitor.

        capacitor add ios exited with exit code 1.

        Re-running this command with the --verbose flag may provide more
        information.

Reading through this error, in my root directory, it is missing the www directory.  It was looking for this directory structure

¬ SAFS
   ¬ e2e
   ¬ node_modules
   ¬ resources
   ¬ src
   ¬ www

Instead it was receiving.  Missing the www directory.

¬ SAFS
   ¬ e2e
   ¬ node_modules
   ¬ resources
   ¬ src

 

Resolving the capacitor errors

Both of the above errors reached the same point.  And I needed to execute an ionic build command

ionic build --run

To see what impact this has on the structure to date.

The response I received was 

Compiling @angular/core : es2015 as esm2015
Compiling @angular/fire : es2015 as esm2015
Compiling @angular/common : es2015 as esm2015
Compiling @angular/platform-browser : es2015 as esm2015
Compiling @asymmetrik/ngx-leaflet : module as esm5
Compiling @angular/forms : es2015 as esm2015
Compiling @angular/router : es2015 as esm2015
Compiling @angular/platform-browser-dynamic : es2015 as esm2015
Compiling @angular/fire/firestore : es2015 as esm2015
Compiling @angular/fire/auth : es2015 as esm2015
Compiling @angular/common/http : es2015 as esm2015
Compiling @ionic/storage : es2015 as esm2015
Compiling @angular/service-worker : es2015 as esm2015
Compiling @ionic/angular : es2015 as esm2015

chunk {} 0.js, 0.js.map () 35.7 kB  [rendered]
chunk {1} 1.js, 1.js.map () 53.9 kB  [rendered]
chunk {2} 2.js, 2.js.map () 91.2 kB  [rendered]
chunk {3} 3.js, 3.js.map () 7.91 kB  [rendered]
chunk {4} 4.js, 4.js.map () 21 kB  [rendered]
chunk {5} 5.js, 5.js.map () 5.1 kB  [rendered]
chunk {6} 6.js, 6.js.map () 37.4 kB  [rendered]
chunk {7} 7.js, 7.js.map () 20.2 kB  [rendered]
chunk {8} 8.js, 8.js.map () 13.7 kB  [rendered]
chunk {9} 9.js, 9.js.map () 11 kB  [rendered]
chunk {10} 10.js, 10.js.map () 19.2 kB  [rendered]
chunk {11} 11.js, 11.js.map () 90.8 kB  [rendered]
chunk {12} 12.js, 12.js.map () 33.5 kB  [rendered]
chunk {13} 13.js, 13.js.map () 4.62 kB  [rendered]
chunk {14} 14.js, 14.js.map () 19.4 kB  [rendered]
chunk {15} 15.js, 15.js.map () 25 kB  [rendered]
chunk {16} 16.js, 16.js.map () 45 kB  [rendered]
chunk {17} 17.js, 17.js.map () 83 kB  [rendered]
chunk {18} 18.js, 18.js.map () 18.9 kB  [rendered]
chunk {19} 19.js, 19.js.map () 50.4 kB  [rendered]
chunk {20} 20.js, 20.js.map () 33.7 kB  [rendered]
chunk {21} 21.js, 21.js.map () 50.6 kB  [rendered]
chunk {22} 22.js, 22.js.map () 26.1 kB  [rendered]
chunk {23} 23.js, 23.js.map () 23.1 kB  [rendered]
chunk {24} 24.js, 24.js.map () 22.3 kB  [rendered]
chunk {25} 25.js, 25.js.map () 32.7 kB  [rendered]
chunk {26} 26.js, 26.js.map () 64.9 kB  [rendered]
chunk {27} 27.js, 27.js.map () 17.6 kB  [rendered]
chunk {28} 28.js, 28.js.map () 9.65 kB  [rendered]
chunk {29} 29.js, 29.js.map () 54 kB  [rendered]
chunk {30} 30.js, 30.js.map () 37.3 kB  [rendered]
chunk {31} 31.js, 31.js.map () 45.7 kB  [rendered]
chunk {32} 32.js, 32.js.map () 35.6 kB  [rendered]
chunk {33} 33.js, 33.js.map () 79.6 kB  [rendered]
chunk {34} 34.js, 34.js.map () 9.67 kB  [rendered]
chunk {35} 35.js, 35.js.map () 11.4 kB  [rendered]
chunk {36} 36.js, 36.js.map () 28.1 kB  [rendered]
chunk {37} 37.js, 37.js.map () 18.3 kB  [rendered]
chunk {38} 38.js, 38.js.map () 2.85 kB  [rendered]
chunk {39} 39.js, 39.js.map () 22.2 kB  [rendered]
chunk {40} 40.js, 40.js.map () 29.2 kB  [rendered]
chunk {41} 41.js, 41.js.map () 21.4 kB  [rendered]
chunk {42} 42.js, 42.js.map () 25.6 kB  [rendered]
chunk {common} common.js, common.js.map (common) 25.3 kB  [rendered]
chunk {firebase-auth} firebase-auth.js, firebase-auth.js.map (firebase-auth) 255 kB  [rendered]
chunk {focus-visible-15ada7f7-js} focus-visible-15ada7f7-js.js, focus-visible-15ada7f7-js.js.map (focus-visible-15ada7f7-js) 2.04 kB  [rendered]
chunk {input-shims-ba28b23a-js} input-shims-ba28b23a-js.js, input-shims-ba28b23a-js.js.map (input-shims-ba28b23a-js) 20.8 kB  [rendered]
chunk {keyboard-dd970efc-js} keyboard-dd970efc-js.js, keyboard-dd970efc-js.js.map (keyboard-dd970efc-js) 6.31 kB  [rendered]
chunk {main} main.js, main.js.map (main) 95.9 kB [initial] [rendered]
chunk {pages-about-about-module} pages-about-about-module.js, pages-about-about-module.js.map (pages-about-about-module) 15.9 kB  [rendered]
chunk {pages-az-listing-az-listing-module} pages-az-listing-az-listing-module.js, pages-az-listing-az-listing-module.js.map (pages-az-listing-az-listing-module) 10 kB  [rendered]
chunk {pages-fish-detail-fish-detail-module} pages-fish-detail-fish-detail-module.js, pages-fish-detail-fish-detail-module.js.map (pages-fish-detail-fish-detail-module) 33.7 kB  [rendered]
chunk {pages-glossary-detail-glossary-detail-module} pages-glossary-detail-glossary-detail-module.js, pages-glossary-detail-glossary-detail-module.js.map (pages-glossary-detail-glossary-detail-module) 7.76 kB  [rendered]
chunk {pages-glossary-glossary-module} pages-glossary-glossary-module.js, pages-glossary-glossary-module.js.map (pages-glossary-glossary-module) 9.21 kB  [rendered]
chunk {pages-home-home-module} pages-home-home-module.js, pages-home-home-module.js.map (pages-home-home-module) 2.76 kB  [rendered]
chunk {pages-jurisdiction-jurisdiction-module} pages-jurisdiction-jurisdiction-module.js, pages-jurisdiction-jurisdiction-module.js.map (pages-jurisdiction-jurisdiction-module) 17.2 kB  [rendered]
chunk {pages-search-search-module} pages-search-search-module.js, pages-search-search-module.js.map (pages-search-search-module) 24.1 kB  [rendered]
chunk {polyfills} polyfills.js, polyfills.js.map (polyfills) 265 kB [initial] [rendered]
chunk {polyfills-core-js} polyfills-core-js.js, polyfills-core-js.js.map (polyfills-core-js) 156 kB  [rendered]
chunk {polyfills-css-shim} polyfills-css-shim.js, polyfills-css-shim.js.map (polyfills-css-shim) 13 kB  [rendered]
chunk {polyfills-dom} polyfills-dom.js, polyfills-dom.js.map (polyfills-dom) 54.9 kB  [rendered]
chunk {polyfills-es5} polyfills-es5.js, polyfills-es5.js.map (polyfills-es5) 582 kB [initial] [rendered]
chunk {runtime} runtime.js, runtime.js.map (runtime) 10.1 kB [entry] [rendered]
chunk {shadow-css-c63963b5-js} shadow-css-c63963b5-js.js, shadow-css-c63963b5-js.js.map (shadow-css-c63963b5-js) 16.4 kB  [rendered]
chunk {status-tap-0b3e89c4-js} status-tap-0b3e89c4-js.js, status-tap-0b3e89c4-js.js.map (status-tap-0b3e89c4-js) 1.47 kB  [rendered]
chunk {styles} styles.js, styles.js.map (styles) 129 kB [initial] [rendered]
chunk {swipe-back-2c765762-js} swipe-back-2c765762-js.js, swipe-back-2c765762-js.js.map (swipe-back-2c765762-js) 2.75 kB  [rendered]
chunk {swiper-bundle-95afeea2-js} swiper-bundle-95afeea2-js.js, swiper-bundle-95afeea2-js.js.map (swiper-bundle-95afeea2-js) 216 kB  [rendered]
chunk {tap-click-9e4a1234-js} tap-click-9e4a1234-js.js, tap-click-9e4a1234-js.js.map (tap-click-9e4a1234-js) 5.9 kB  [rendered]
chunk {vendor} vendor.js, vendor.js.map (vendor) 6.76 MB [initial] [rendered]

 

And now to see if the ionic capacitor command will kick start the app

ionic capacitor open ios
capacitor add ios
[capacitor]   Found 4 Cordova plugins for ios
[capacitor]     cordova-plugin-advanced-http (2.0.1)
[capacitor]     cordova-plugin-device (2.0.2)
[capacitor]     cordova-plugin-file (6.0.2)
[capacitor]     cordova-sqlite-storage (5.1.0)
[capacitor]   Found 0 Capacitor plugins for ios:
[capacitor]   Found 4 Cordova plugins for ios
[capacitor]     cordova-plugin-advanced-http (2.0.1)
[capacitor]     cordova-plugin-device (2.0.2)
[capacitor]     cordova-plugin-file (6.0.2)
[capacitor]     cordova-sqlite-storage (5.1.0)
[capacitor]   Found 5 incompatible Cordova plugins for ios, skipped install
[capacitor]     cordova-plugin-ionic-keyboard (2.2.0)
[capacitor]     cordova-plugin-ionic-webview (2.5.3)
[capacitor]     cordova-plugin-splashscreen (5.0.2)
[capacitor]     cordova-plugin-statusbar (2.4.2)
[capacitor]     cordova-plugin-whitelist (1.3.3)
[capacitor]
[capacitor] Now you can run npx cap open ios to launch Xcode
> capacitor open ios

 

The app opened in Xcode.  After a few updates to deprecated frameworks:

  • AssetsLibrary.framework switched over to Photos.framework
  • MobileCoreServices.framework switched to CoreServices.framework

And the iOS deployment updated from 8.0 to 12.0.  The app was back up and running!

Discovery mode.  Now time to review the changes required.  Assess whether better to rebuild the app, or patch for the short term.

 

Short and sharp solution

If you have no interest in reading through how this situation was resolved, then following are the series of steps to run.  They are a truncated version without all the testing and descriptions from above.

npm install
ionic build --run
ionic capacitor open ios

Done.

While it is great to go to the immediate steps, make sure you have the software installed before executing those steps.  Not sure, then the software step up quick steps are:

npm install -g ios-sim
brew install ios-deploy
npm install -g cordova
npm install -g ionic

 

Related articles

Andrew Fletcher16 Aug 2022

How to handle a lost KeyStore password in Android?

If you have a situation where either you have forgotten a Keystore password or change of developers and the password wasn't sent across.... what to do? &nbsp;However, your app lives on and needs to be updated! &nbsp; Possible solutions grade.properties This is a great starting point....
Andrew Fletcher08 Aug 2022

How to update package.json dependencies to the latest version?

This article works through the steps to update&nbsp;dependencies in package.json file to the latest version. Use npm-check-updates or npm outdated to suggest the latest versions. npm-check-updates is a utility that automatically adjusts a package.json with the latest version of all...