This project contains the core software used to deploy Boma apps to the iOS and Android store. It comprises an ember project wrapped with cordova.
[[TOC]]
Run the following script to build the various dependencies required for the web browser development environment.
sh environment.sh && nvm use
> ember s
To setup the project for cordova you have to complete the following steps.
- Install the dependencies for iOS and Android builds on your local development environment
- Configure the app and add the assets required for a successful build
- Setup push notifications
- Build Dependencies
- Build the app and deploy to a a device.
iOS builds to submit to the stores are generated using xCode. Follow these steps to install xCode and relevant command line tools and the Transporter app which is used for submitting builds.
- Get the latest version of xCode from the mac OS app store
- Open the app and follow the prompts to install the command line tools
- Download the transporter app from the mac OS app store to deliver builds
For Android builds use Android Studio to manage the SDKs installed on your computer. Follow these steps to install all the required software.
- Download and install Android Studio from https://developer.android.com/studio
- Open the app and from the home screen click the 'More Actions' link and select SDK manager from the dropdown
- Check the box for 'Show Package Details' (bottom right)
- In SDK platforms check 'SDK Platform 33' and 'Source for Android 33'
- In SDK tools check '33.0.1' from the 'Android SDK build tools' menu and 'SDK command line tools latest' (8.0 currently) from 'Android SDK Command line Tools'.
- Include the path to android build tools in your PATH.
- Install JDK 11.0.16.1 following the instructions here https://docs.oracle.com/en/java/javase/15/install/installation-jdk-macos.html#GUID-F575EB4A-70D3-4AB4-A20E-DBE95171AB5F
- Set JAVA_HOME in your path to the JDK location (similar to
/Library/Java/JavaVirtualMachines/jdk-11.0.16.1.jdk/Contents/Home
) - You may have to reboot your computer :-)
To successfully build the app you mus set an app ID in the config.xml and include the following assets in /res
folder.
- Open res/config.xml
- Update
<widget id=''>
to reflect app ID for current project in the format com.{festival_name}.boma
The XD templates for designers include instructions on how to provide the assets at the right size.
Export icon and splash as .svg
and android-splash as .png
.
Place the exported files in the /res directory
- icon.svg
- splash.svg
- android-splash.png
Additionally export the splash image as a jpg and place it in public/assets/images
directory. This is for the 'client side' loading screen.
icon.svg
is used for the app icon for all platforms.
splash.svg
is used when the app is opening on iOS.
android-splash.png
is used for android only, it renders in the centre of the screen and a static background colour can be set in config.xml AndroidWindowSplashScreenBackground
.
Reference http://corber.io/pages/workflow/icon_splash_management.html for icon.svg and splash.svg sizes and https://developer.android.com/develop/ui/views/launch/splash-screen for android-splash.png.
- Login to firebase and add project for android using app ID defined above.
- Download the google-services.json file and place it in the /res directory
- Create the p8 cert file
- Go to the Apple Developer Member center, then go to the "Keys" menu and add a new key.
- Give a name to your key, tick the "Apple Push Notifications Service" box and download the .p8 file.
NB: You will have to create a new gorush server per p8 cert. Instructions on how to achieve this can be found in the https://gitlab.com/boma-hq/gorush-with-basic-http-auth readme.
run sh build.sh
to recreate the cordova project including adding relevant plugins and platforms.
Convenient build commands have been implemented using npm scripts.
To build for al platforms and deploy to all devices
npm run build:all
To build for all platoforms in production and deploy for all devices
npm run build:all:production
To build for iOS and open xCode
npm run build:ios
To build and iOS and open xCode in production
npm run build:ios:production
To build for android and flash on to the attached phone
npm run build:android
To build for android in production and flash on to the attached phone
npm run build:android:production
A comprehensive list of CSS variables have been defined to signifcantly reduce the amount of CSS required for to apply a festival's skin to the app.
The list of CSS variables along with documentation can be found in params-overlay.css
. When in doubt use the web inspector to inspect the element, the appropriate variable is shown in the styling section of the inspect window.
To style the apps:-
- Create a new CSS file for this app and save it in
app/styles/
- Copy the CSS variables from
params-overlay.css
into the file. - Import the new CSS file in app.css using the
@import "path-to-css-file.css"
syntax - Amend the CSS variables to reflect the styling of the app.
- Add any additional CSS required to achieve the desired styling below the CSS variables.
Configuration for the app currently spans:
- the ember configuration file found in
config/environments.js
- The
Festival
andOrganisation
models in the postgres db (and syndicated to the app via couch/pouch db). - Attributes on the
events
andarticles
controllers in the ember project.
Param | Type | purpose | example |
---|---|---|---|
*emberPouch.localDb | string | the local pouchdb database name | kambe_events_1 |
*emberPouch.remoteDb | string | the remote couchdb database name | kambe_events_1 |
multiFestivalApp | bool | enables multi festival mode | true |
clashfinderEnabled | bool | enables the clashfinder view | true |
fallbackImageFileName | string | fallback image when img cache fails and network isn't available | "splash.jpg" |
organisationId | int | the id of the organisation | 1 |
festivalId | int | the id of the festival (default festival if multi festival app mode is enabled) | 1 |
articleAudioTagId | int | the tag id for the article tag 'audio' (legacy) | 254 |
bundleVersion | int | the version of the image and data bundle included in this release | 1 |
communityArticlesEnabled | bool | enables/disables community articles | true |
communityEventsEnabled | bool | enables/disables community events | true |
festivalHome | object | the route the app opens up to inside festival time* | {routeName: 'events', params: {}} |
communityHome | object | the route the app opens up to outside festival time* | {routeName: 'articles', params: {}} |
eventFilterTagType | string | use event tags or production tags for filters | 'event' or 'production' |
subtleWallet | bool | show wallet in left sidebar menu or not | true |
enableLessWordyCopy | bool | allow users to opt to see short descriptions for productions | true |
subtleWallet | bool | This removes the link to the wallet from the left sidebar and puts a reference to it in the Settings page instead | true |
mapConfig | object | see Configuring the Map |
* You can find these by checking in the /_utils
of the couchdb in question or using the following command in the rails console Festival.find(FESTIVAL_ID).couchdb_name
Param | Type | purpose | example |
---|---|---|---|
app_bundle_id | string | used for the app update nag links | "com.boom.boma" |
current_app_version | string | used for the app update nag links | "40.0.1" |
apple_app_id | string | used for the app update nag links | "1255976495" |
Param | Type | purpose | example |
---|---|---|---|
enable_festival_mode_at | datetime | enable festival mode at | Mon, 01 Aug 2022 11:00:00.992000000 UTC +00:00, |
disable_festival_mode_at | datetime | disable festival mode at | Thu, 01 Sep 2022 11:00:00.019000000 UTC +00:00 |
clashfinder_start_hour | int | the time the day starts on the clashfinder view | 5 |
schedule_modal_type | string | whether to show the event or production modals when clicking on an event | 'event|production' |
use_production_name_for_event_name | boolean | choose to use either the production name or set an individual event name | true |
data_structure_version | string | v1 or v2 or data structure (v1 one couchdb per Festival, v2 one couchdb per Organisation) (legacy) | 'v1|v2' |
short_time_format | string | the format used when printing the short time format, use https://apidock.com/ruby/DateTime/strftime for reference | "%a %H:%M" |
require_production_images | boolean | validate for prescense of images when creating/editing productions | true |
require_venue_images | boolean | validate for prescense of images when creating/editing venues | true |
The following configurations are available for the events lists
Param | Type | purpose | example |
---|---|---|---|
displayFormat | string | whether to display the events in a list or grid | "list |
modalType | string | type of modal to open when clicking on an event | "productionModal |
hideImage | bool | whether the image should be hidden on the modal view | true |
venueNameAsThumbnail | bool | whether the venue name should be included instead of the image thumbnail | true |
linkOnly | bool | open a link in inappbrowser instead of opening modal | true |
Configuration of what is rendered in the events templates is done through query parameters.
The following query parameters are available.
selectedTags
(an array of tag ids to include, NB: these tags removed when filters are reset, to retain them use persistentSelectedTags)selectedExcludedTags
(an array of tag ids to exclude)preferences
(boolean, if true show preferred events)selectedVenues
(an array of venue ids to include)selectedDays
(an array of days to include)persistentSelectedTags
(an array of tag ids to include, these are not removed when filters are reset)
Any one or combination of these query params can be used to refine the list of events.
You can also provide the following query_params to customise the template
viewType
(set to clashfinder to show clashfinder view)pageName
(the name to be shown in the header at the top of the articles template)
Configuration of what is rendered in the articles templates is done through query parameters.
The following query parameters are available.
articleType
(matches the article_type attribute on the Article model)selectedTags
(an array of tag ids to include)selectedExcludedTags
(an array of tag ids to exclude)selectedCreator
(boolean, if true show articles created by current wallet address)preferences
(boolean, if true show preferred articles)
Any one or combination of these query params can be used to refine the list of articles.
You can also provide the following query_params to customise the template
pageName
(the name to be shown in the header at the top of the articles template)tagType
(refines the list of tags showed in the filters, matches the tag_type attribute on the Tag model)
There is an attribute on the article_type model passing this as a query_param in an ember route will return a list of articles by that article_type.
<a {{action "goToRoute" 'articles'
(query-params
articleType='boma_news_article'
)
}}>News</a>
Would return all articles with article_type with boma_news_article.
Passing an array of tag ids as query parameters returns a list of articles that are tagged with one or both of those tags
<a {{action "goToRoute" 'articles'
(query-params
articleType='boma_news_article'
selectedTags=[1]
selectedExcludedTags=''
pageName='Tag 1'
)
}}>News</a>
*Tag ids are currently set in the config/enviroment.js file and converted to the appropriate format in app/components/app-left-sidebar.js
<a {{action "goToRoute" 'articles'
(query-params
articleType='boma_news_article'
selectedTags=''
selectedExcludedTags=[1]
pageName='Not Tag 1'
tagType='news_tag'
)
}}>News</a>
*Tag ids are currently set in the config/enviroment.js file and converted to the appropriate format in app/components/app-left-sidebar.js
Populate the tagType query_params with the matching tag_type to include a list of these tags in the right hand sidebar filters list.
<a {{action "goToRoute" 'articles'
(query-params
articleType='boma_news_article'
selectedTags=''
selectedExcludedTags=[1]
pageName='Not Tag 1'
tagType='news_tag'
)
}}>News</a>
NB this needs improvment, for now, the controller needs to include the following elements
The controller needs
- registerFormElement, next, prev and goTo actions (all linking to actions in the form.js service)
- resetForm (to reset all form elements to their original state)
- Validations (A list of validations for form elements)
- formPanes array listing all ids in form (list of ids for form-panes)
- currentPaneIndex: alias('formService.currentPaneIndex')
- formService: service('form')
- apiEndpoint: ENV['apiEndpoint']
- loading: false,
Form navigation and breadcrumb is handled by a set of components which can be configured to have as many steps are neccesary.
To configure a form create a wrapping {{form-wrap}}
component and nest {{form-pane}}
components inside it including the following attributes:
-
id
required - (a unique id for this form-pane) -
registerFormElement
required - (an action which triggers theregisterFormElement
method on the form service) -
formPanes
required - (the array of all the form pane ids) -
currentPaneIndex
required - (the index of the currentPane, handled by the form service) -
next
optional - (the action to complete when a user clicks next, leave blank to exclude a next action) •nextButtonText
optional - (the text of the next button) -
loading
optional - -
prev
optional - (the action to complete when a user clicks prev, leave blank to exclude a prev action)
Example...
{{#form-pane
id="image"
registerFormElement=(action "registerFormElement")
next=(action imageNextAction)
nextButtonText=imageNextButtonText
prev=(action "prev")
formPanes=formPanes
currentPaneIndex=currentPaneIndex
}}
Form validations are handled with custom next and previous actions and use the ember-cp-validations library.
- Convert the map image supplied by the client into four equal slices, export as jpg for web
- Place the images in the public/assets/images/ folder of the project
Note the filenames, they should end with a number as shown below e.g
map_01.jpg
1 | 2 |
3 | 4 |
- Set the following config in config/environment.js
imageFilenameBase
should be the part of the map filename before the numbers. E.g map_0imageFilenameExt
should be the file extension. E.g jpgxtop
should be the latitude of the top of the imagexright
should be the longitude of the right of the imagexbottom
should be the latitude of the bottom of the imagexleft
should be the longitude of the left of the image
- Test the map config is correct following the instructions in here
- Update your local postgres database following the instructions https://gitlab.com/boma-hq/boma-api#install-heroku-cli-and-get-and-restore-the-latest-production-database
- Run the following rake command using your local copy of the boma-api project to download the bundle of images. Once complete the images will be stored in
/images/{festival_id}
of the api project location.
> bundle exec rake bundle:images\[festival_id\]
- Wait for the couchdb cache to be renewed (or manually dump the cache).
- Run the following rake command using the heroku cli. This will set the
bundled_at
attribute on the relevant couchdb record. This is used by the client when deciding whether to use the bundled image or to cache a new one from the CDN.
> heroku run rake bundle:touch\[festival_id\] -a boma-production
You will need pouchdb dumps for the Festival
records (festival.json), for the festival schedule (Production
, Event
, Venue
and Tag
) (dump.json) and if token functionality is in use by this festival for TokenTypes
(tokens.json).
- Using the pouch-dump project (https://gitlab.com/boma-hq/pouch-dump) make the dumps
- festival data ->
node pouch-dump.js --db {URL_TO_POUCHDB_DATABASE} --view {FESTIVAL_DESIGN_DOC_NAME}/this_festival --filename festival.json
- festival schedule ->
node pouch-dump.js --db {URL_TO_POUCHDB_DATABASE} --view {FESTIVAL_DESIGN_DOC_NAME}/festival_dump --filename dump.json
- token_types ->
node pouch-dump.js --db {URL_TO_POUCHDB_DATABASE} --view {FESTIVAL_DESIGN_DOC_NAME}/all_tokentypes --filename tokens.json
- Place the dumps in the /public/assets/ directory of the client project for this festival.
Use the couchdb interface at /_utils
to determine the value of FESTIVAL_DESIGN_DOC_NAME
.
Test the app using this script on both iOS and Android
https://docs.google.com/spreadsheets/d/1Ssd6d3a17k8zKBYz1e9MHOY-w6hW_UR-i8CHW2McOkU/edit#gid=0
Test the map alignment is correct using open street map tiles and a geograhpical feature (e.g a lake) set the ‘testOverlayWithVectorTilesEnabled‘ variable im app-maplbre.js to true. You should see an opaque version of your designed map overlaid on top of the open street map tiles for the same location.
To test overlaid GPS Maps on iOS devices.
- Create a .gpx file in the following format.
<gpx>
<wpt lat="39.97312319514796" lon="-7.186479420799401"></wpt>
</gpx>
Add one node for each point, adding multiple points will simulate movement.
- Flash the build you want to test onto a iOS device
- Click the 'simulate location' icon in the toolbar above the logs in XCode and upload the .gpx file.
- Click the 'simulate locaiton' icon again and select the location. You should now be able to use the phones location services to verify that the lat/long coordinates you've provided in the gpx file are correct.
NB: There is currently no known method of mocking the GPS location on Android devices.
The app behaves differently during the period whilst the festival is taking place.
To test this functionality set the Date, Time and Timezone appropriatly on the device you are using the test.
To test local notifications set the fakeTime
attribute in the preference-toggle.js service. This creates notifications that are fired two minutes after clicking on the heart to add the event to a schedule.
Refer to https://gitlab.com/boma-hq/boma-api#testing-push-notifications when testing push notifications.
It is not possible to flash a new release built locally to a device running a build downloaded from the app stores.
To make it possible to test the upgrade path the simplest way is to:-
- Install the production release from the app store.
- Use the TestFlight app to install the upgrade.
- If your Google account is already enrolled on the internal beta testing programme use the link provided in the Google Play developer console to 'Leave the Programme'
- Uninstall the app on your device and clear the Google Play app cache.
- Install the production release from Google Play app on your device.
- Use the link provided in Google Play developer console to enroll onto the internal beta testing programme.
- Use the Google Play app to install the upgrade.
NB: It is also possible to test this by maintaining a local build of the production version of the app, flashing this to both devices and then flashing the updated release over it.
To allow beta testing of unpublished festivals the app has the functionality to show festivals that have a aasm_state
of preview
to users who have any token that has the word 'testers' in the name.
Use the rails console to set the aasm_state
to preview
for the festival you want users to test.
- Login to https://appstoreconnect.apple.com and create a new app.
a) Set platform at iOS
b) Add a name
c) Set primary language to UK English
d) Use the bundle id you've just setup
e) Set SKU to be a unique value for this app (e.g gb-2023-1)
f) Click create.
- Populate marketing details
- Select 'Manually Release this Version'.
- Create a Google Play Developer Account and Login at https://play.google.com/console/u/0/developers/?pli=1
- Click 'Create' in the top right hand corner to create a new app.
- Follow the steps shown to create an app profile.
Increment the version number in both
- corber/cordova/config.xml and
- package.json
- Open up the app using the iPhone 14 Plus emulator to get 6.7" screenshots and the iPhone 8 Plus emulator to get 5.5" screenshots
- Use the Apple shortcut ⌘ + S to save the screenshots to your desktop
- Create screenshots that are 16:9 (I've found it simplest to do this using the screenshots created for iOS above and cropping them manually in Photoshop.)
npm run build:ios:production
- Use XCode to create and archive (Product->Archive) and export the package (ipa file)
- Upload using the transporter app (https://apps.apple.com/us/app/transporter/id1450874784?mt=12)
- Wait for the build to process
- Create the release on appstore connect and submit for review
- Tag the release and push to the remote repo
> git tag -a {ORGANISATION_NAME}-{APP_VERSION} -m "{ORGANISATION_NAME}-{APP_VERSION}"
> git push origin {ORGANISATION_NAME}-{APP_VERSION}
Google Play requires that new apps are uploaded using the .aab bundle format. The apps aren't required to be zipaligned just signed with jarsigner.
- Generate a keystore
Run the following command replacing KEYSTORE_NAME with the name of the file (e.g greenbelt2024.keystore) and ALIAS_NAME with an alias which refers to this app (e.g greenbelt2024).
You will be asked the following questions.
- What is your first and last name?
- What is the name of your organizational unit?
- What is the name of your organization?
- What is the name of your City or Locality?
- What is the name of your State or Province?
- What is the two-letter country code for this unit? (Ususally UK)
*** Carefully store the file, your KEYSTORE_NAME and ALIAS_NAME and the associated passwords as without them an update to the app cannot be deployed. ****
> keytool -genkey -v -keystore KEYSTORE_NAME -alias ALIAS_NAME -keyalg RSA -keysize 2048 -validity 10000
Useful Resource -> https://stackoverflow.com/questions/33026847/how-is-one-supposed-to-answer-java-keystore-questions-that-keytool-asks
- Build the package
Run the following command to create a package.
> npm run build:android:production:release:aab
The command create a file called app-release.aab at `/corber/cordova/platforms/android/app/build/outputs/bundle/release/app-release.aab`.
- Sign the aab.
Run the following command to sign the package with jarsigner
> jarsigner -verbose -sigalg SHA1withRSA -digestalg SHA1 -keystore {PATH_TO_KEYSTORE} -signedjar {APK_NAME}.aab {PATH_TO_APK} {KEYSTORE_ALIAS}
Replace PATH_TO_KEYSTORE with the absolute path to the keystore file on your computer
Replace APK_NANE with the filename you'd like the signed apk to have
Replace PATH_TO_APK with the path to the `app-release.aab` file as detailed above
Replace KEYSTORE_ALIAS with the alias you set when creating the keystore file.
- Upload to google play store, create the release and submit for review.
npm run build:android:production:release:apk
- zipalign with
~/Library/Android/sdk/build-tools/31.0.0/zipalign -v 4 {PATH_TO_app-release-unsigned.apk} {APK_NAME}.apk
- sign the apk with
~/Library/Android/sdk/build-tools/31.0.0/apksigner sign --ks {PATH_TO_KEYSTORE} --ks-pass pass:{KEYSTORE_PASS} --v1-signing-enabled true --v2-signing-enabled true {PATH_TO_APK}
- Upload to google play store, create the release and submit for review.
- Tag the release and push to the remote repo
> git tag -a {ORGANISATION_NAME}-{APP_VERSION} -m "{ORGANISATION_NAME}-{APP_VERSION}"
> git push origin {ORGANISATION_NAME}-{APP_VERSION}
To allow developers to watch changes to the cordova project between releases there is a sub repo for files located in the corber/cordova/platforms
directory.
The git repo is initialised when building-dependencies.
When completing the deployment of a new release it's important to check the changes, commit them and tag them with the release version. This allows a developer to review the diff to ensure confidence in the release that is being deployed.
- Commit the changes in the cordova platforms sub repo
> cd corber/cordova/platforms
> git add .
> git commit -m "{MEANINGFUL COMMIT MESSAGE}"
> git push origin {BRANCH_NAME}
- Tag the changes in the cordova platorms sub repo and push to the remote repo
> git tag -a {ORGANISATION_NAME}-{APP_VERSION} -m "{ORGANISATION_NAME}-{APP_VERSION}"
> git push origin {ORGANISATION_NAME}-{APP_VERSION}
A manifest of all apps can be found at here
Make sure node is up to date with at least the LTS (long term support) release.
LTS -> https://github.com/nodejs/Release Stable -> https://github.com/nodejs/Release
To update node:
- Open
./environment.sh
- Amend the version of node in both the
nvm use
andnvm install
commands and save. - Run
sh environment.sh
to install the latest version of node and build the dependencies.
Ember has a very fast release cycle, it's best practise to keep this project up to date with at least the LTS (Long term support) release of ember-cli but ideally the current stable release.
LTS -> https://emberjs.com/releases/lts/ Stable -> https://emberjs.com/releases/release/
There is an ember tool to update the project, including any changes to config / core files any changes in syntax
To run an update:
- Clear all deprecation warning both in the browser console and in the ember server output
- Commit all changes (
ember-cli-update
only works if your git stage is completely empty) - Run
ember-cli-update --to version-number
to upgrade to a specific release. Upgrade by moving up the minor versions (or at least by working through LTS). - Update all other dependencies. Find them using
npm outdated
and update one by one usernpm update PACKAGE_NAME
. - Check all
boma-digital
mirrored packages are as up to date as possible with the master branches of the repo the mirror was forked from (search the package.json for dependencies withgithub:
orgit+
). - Judiciously test the release following the steps outlined in Testing
- Update the
ember-cli
global dependency in./environment.sh
New releases of cordova-cli are announced at https://github.com/apache/cordova-cli/blob/master/RELEASENOTES.md
To upgrade:
- Update the cordova-cli version to the desired release in environemnt.sh
- Run
sh environment.sh
from the root for each project you want to upgrade
New releases of cordova-android are documented at https://github.com/apache/cordova-android/blob/master/RELEASENOTES.md New releases of cordova-ios are documented at https://github.com/apache/cordova-ios
To upgrade:
- Update the cordova-android or cordova-ios version in the commands to add the platforms in build.sh
> corber proxy platform add android@12
> corber proxy platform add ios@12
- Run
sh build.sh
from the root for each project you want to upgrade
Check each of the individual github repos to check for new releases of the plugins used for this project.
Where plugins are being installed from a internal fork (on boma-digital github) check the changes against the parent repository since the fork and make any appropriate actions.
To upgrade:
- Update the plugin version in the commands to add the plugins in build.sh
e.g:
> corber proxy plugin add cordova-plugin-statusbar@4.0.0
- Run
sh build.sh
from the root for each project you want to upgrade
!IMPORTANT Update one plugin at a time and test the project builds (for both platforms) and that there aren't any regression bugs. Not doing this makes debugging issues very challenging.