Using Google Sheet as CMS for your App - Part 1
Imagine you had an easy to understand CMS without too much overhead, just to add translations and a bit of content for your (Xamarin) app. A CMS with an “excel-like” interface, an interface most of your customers would understand without even a training? Say “Hi” to Google Sheets & Azure Functions!
Any time I start a new app project the same question arises: how do we maintain content in a (Xamarin) app:
- A CMS can be used but brings additional costs and might be overkill. It also might need a data connection to retrieve all content;
- Static translations or resource files is an option but makes it harder to change content.
Just recently I had a customer who literaly said: “I don’t want a CMS. It is slow, hard to maintain, difficult to quickly add new content. Can you use Google Docs?”. Just a few minutes of research and I had it up and running!
In this first part I will explain how to use a Google Sheet as a CMS for your Xamarin App by connecting your app straight to the Google Sheets API. In another post I will create a more reliable and professional API by adding Azure Functions as a proxy so we can add caching.
The sample
For this post I will create a simple app with a list of jobs and a detail page. I will use Xamarin Forms to keep it simple and clean.
List | Details |
---|---|
<img src="./app_1.png" alt="Job list"> | <img src="./app_2.png" alt="Job details"> |
Enable the Google Sheets API
What needs to be done is this: in the Google Developers Console the Google Sheets Api needs to be enabled:
<img src="./google_console.png" alt="Google Console">
The next step is to generate a secret json file:
<img src="./secret_1.png" alt="Secret 1">
<img src="./secret_2.png" alt="Secret 2">
Keep the secret.json file, we will use this later.
Create a new Google Sheet
The sheet I use is simple:
<img src="./google_sheet.png" alt="The sheet">
To enable access for the Sheets API you have to add the API user’s email to the share permissions.
- Copy the email address from the secret.json file
- click on Share (the blue button at the right top of the sheet) and add the email address:
<img src="./permissions_1.png" alt="Permissions 1">
<img src="./permissions_2.png" alt="Permissions 2">
The App
I created a Xamarin Forms app and added the following nuget packages to the NetStandard core project
<img src="./adding_packages.png" alt="Adding packages">
Next I added the secret.json file to the iOS and Android project:
- for iOS, just add it to the root
- for Android, add it to the Assets folder
<img src="./added_json.png" alt="Added json">
For Android set the Build Action to AndroidAsset:
<img src="./set_build_action.png" alt="Build Action">
The JobService
The JobService is responsible for getting the content from the sheet and map it to the model. Set the required parameters and map the colums to the model:
var sheetData = await provider.GetAsync(filePath,
"Job offers", // sheet tab name
"SHEET ID", // The sheet id (from the url)
"A:G") // the range
.ConfigureAwait(false);
var sheetMapper = new SheetMapper().AddConfigFor<JobOffer>(cfg => cfg
.MapColumn(column => column.WithHeader("Title").MapTo(m => m.Title))
.MapColumn(column => column.WithHeader("Introduction").MapTo(m => m.Introduction))
.MapColumn(column => column.WithHeader("Text").MapTo(m => m.Text))
.MapColumn(column => column.WithHeader("Tags").MapTo(m => m.Tags))
.MapColumn(column => column.WithHeader("Color").MapTo(m => m.Color))
.MapColumn(column => column.WithHeader("Date").MapTo(m => m.Date))
.MapColumn(column => column.WithHeader("Published")
.WithDefaultValue<bool>(true)
.MapTo(m => m.Published)));
If you look at the source you can see I use the DependencyService to get the file location of the secret file. The problem is that, AFAIK, it is not possible to access a file in Android by path since it is ‘zipped’ into the APK. I created a SecretService on Android and iOS to fix this issue.
What’s next
I didn’t show a lot of code. The code is simple anyway. It took me some time so sort a few things out:
- How to allow access from the API to the sheet (adding the email address from the json file!)
- How to read a json file in Android (with a work around to copy the contents from the asset file to a temp file)
- I added a implementation for protected sheets to the SheetToObjects]( https://github.com/josdeweger/SheetToObjects ) nuget package
I am going to write a post about adding Azure Functions between the app and the sheet as a proxy with caching. Next I will try to add a post about using the HTTP ETag to prevent downloading unnecessary data.
Let me know if you have questions or ideas about using Sheets as a CMS!
Links
App source: GitHub
SheetToObjects library, created by Jos de Weger: SheetToObjects