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-{project}/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