Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
Using Continuous Integration with Xamarin Apps
Search
Greg Shackles
October 08, 2014
Technology
1
780
Using Continuous Integration with Xamarin Apps
Presented at Xamarin Evolve 2014
Greg Shackles
October 08, 2014
Tweet
Share
More Decks by Greg Shackles
See All by Greg Shackles
Building Modern Services with .NET Core 3 and gRPC
gshackles
0
150
Observability-Driven Development: What DevOps is Really About
gshackles
1
270
Monitoring Your Mobile Apps in the Wild
gshackles
1
82
Building Scalable Applications with the Actor Model
gshackles
0
580
Creating a Voice-Driven TV Remote with Azure and Alexa
gshackles
0
97
Build 2017 Recap for Xamarin Developers
gshackles
0
95
Going Serverless: Event-Driven Architecture Without The Infrastructure
gshackles
0
160
Evolve 2016 Redux
gshackles
0
130
Instrumenting Your Mobile Monitoring Strategy
gshackles
0
4.6k
Other Decks in Technology
See All in Technology
WAF に頼りすぎない AWS WAF 運用術 meguro sec #1
izzii
0
460
AWSでRAGを実現する上で感じた3つの大事なこと
ymae
3
1k
AndroidXR 開発ツールごとの できることできないこと
donabe3
0
110
7日間でハッキングをはじめる本をはじめてみませんか?_ITエンジニア本大賞2025
nomizone
2
1.4k
地方拠点で エンジニアリングマネージャーってできるの? 〜地方という制約を楽しむオーナーシップとコミュニティ作り〜
1coin
1
130
【Developers Summit 2025】プロダクトエンジニアから学ぶ、 ユーザーにより高い価値を届ける技術
niwatakeru
2
890
まだ間に合う! エンジニアのための生成AIアプリ開発入門 on AWS
minorun365
PRO
4
580
5分で紹介する生成AIエージェントとAmazon Bedrock Agents / 5-minutes introduction to generative AI agents and Amazon Bedrock Agents
hideakiaoyagi
0
220
バックエンドエンジニアのためのフロントエンド入門 #devsumiC
panda_program
16
6.5k
個人開発から公式機能へ: PlaywrightとRailsをつなげた3年の軌跡
yusukeiwaki
11
2.7k
Moved to https://speakerdeck.com/toshihue/presales-engineer-career-bridging-tech-biz-ja
toshihue
2
550
リアルタイム分析データベースで実現する SQLベースのオブザーバビリティ
mikimatsumoto
0
950
Featured
See All Featured
Six Lessons from altMBA
skipperchong
27
3.6k
Facilitating Awesome Meetings
lara
51
6.2k
Building Better People: How to give real-time feedback that sticks.
wjessup
366
19k
Build your cross-platform service in a week with App Engine
jlugia
229
18k
YesSQL, Process and Tooling at Scale
rocio
171
14k
Building a Modern Day E-commerce SEO Strategy
aleyda
38
7.1k
Scaling GitHub
holman
459
140k
Navigating Team Friction
lara
183
15k
The Straight Up "How To Draw Better" Workshop
denniskardys
232
140k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
45
2.3k
Let's Do A Bunch of Simple Stuff to Make Websites Faster
chriscoyier
507
140k
Keith and Marios Guide to Fast Websites
keithpitt
411
22k
Transcript
Using Continuous Integration with Xamarin Apps Senior Engineer, Olo @gshackles
[email protected]
Greg Shackles
Ship It A Cautionary Tale
None
None
None
None
None
None
None
The Worst by Vitruvius This app is just…the worst.
None
How can we deliver Continuous Awesomeness?
Continuous Integration Let your tools work for you on every
commit
What is Continuous Integration?
What is Continuous Integration? VCS
What is Continuous Integration? VCS CI Server
What is Continuous Integration? VCS CI Server CI Agent
What is Continuous Integration? VCS CI Server CI Agent
Options TFS Jenkins …and more
Delivery TestFlight HockeyApp …and more
CI with Xamarin Apps
Build Agent Setup
Build Agent Setup ▪ OS X machine for iOS builds
- Mac Mini works well
Build Agent Setup ▪ OS X machine for iOS builds
- Mac Mini works well ▪ OS X or Windows machine for Android
Build Agent Setup ▪ OS X machine for iOS builds
- Mac Mini works well ▪ OS X or Windows machine for Android ▪ Install platform SDKs
Build Agent Setup ▪ OS X machine for iOS builds
- Mac Mini works well ▪ OS X or Windows machine for Android ▪ Install platform SDKs ▪ Install Xamarin
Build Agent Setup ▪ OS X machine for iOS builds
- Mac Mini works well ▪ OS X or Windows machine for Android ▪ Install platform SDKs ▪ Install Xamarin ▪ Install agent software for chosen CI server
iOS: Build mdtool build -t:Build -c:AppStore MyAwesomeApp.sln /Applications/Xamarin Studio.app/Contents/MacOS/mdtool
iOS: Package zip -r -y MyAwesomeIosApp.zip path/to/MyAwesomeIosApp.app
Android: Build Windows: msbuild OS X: xbuild xbuild build /t:Build
/p:Configuration=Release MyAwesomeApp.sln
Android: Package (Part 1) Windows: msbuild OS X: xbuild xbuild
build /t:PackageForAndroid /p:Configuration=Release MyAwesomeAndroidApp.csproj
Android: Package (Part 2) jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore
<keystore file> -storepass <keystore password> -signedjar path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp.apk <keystore alias>
Android: Package (Part 2) jarsigner -sigalg SHA1withRSA -digestalg SHA1 -keystore
<keystore file> -storepass <keystore password> -signedjar path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp.apk <keystore alias> zipalign -f -v 4 path/to/MyAwesomeAndroidApp-Signed.apk path/to/MyAwesomeAndroidApp-Aligned.apk
Package Restore NuGet mono NuGet.exe restore path/to/App.sln
Package Restore NuGet mono NuGet.exe restore path/to/App.sln Xamarin Components mono
xamarin-component.exe restore path/to/App.sln
Xamarin.UITest Run using any NUnit runner nunit-console4 path/to/TestAssembly.dll -xml testresults.xml
Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist
Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist ▪ Set
username <key>UserName</key> <string>your_user</string>
Pro Tip: Allow Build to Access UI jetbrains.teamcity.BuildAgent.plist ▪ Set
username <key>UserName</key> <string>your_user</string> ▪ Copy to /Library/LaunchAgents
TestCloud Run your UI tests on hundreds of devices test-cloud.exe
submit path/to/myapp.[ipa|apk] <TestCloud token> --devices <Device Set ID> --series "master" --locale "en_US" --assembly-dir “path/to/bin“ --nunit-xml testresults.xml
FAKE #r @"FAKE/tools/FakeLib.dll" #load "build-helpers/iOS.fsx" open Fake Target
"ios-build" (fun () -> iOS.build "Debug|iPhoneSimulator" ) Target "ios-adhoc" (fun () -> iOS.build "AdHoc|iPhone" ) Target "ios-testflight" (fun () -> iOS.publishToTestFlight() ) "ios-adhoc" ==> "ios-testflight" RunTarget()
FAKE #r @"FAKE/tools/FakeLib.dll" #load "build-helpers/iOS.fsx" open Fake Target
"ios-build" (fun () -> iOS.build "Debug|iPhoneSimulator" ) Target "ios-adhoc" (fun () -> iOS.build "AdHoc|iPhone" ) Target "ios-testflight" (fun () -> iOS.publishToTestFlight() ) "ios-adhoc" ==> "ios-testflight" RunTarget() TeamCityHelper.PublishArtifact "path/to/App.zip" Helpers
FAKE #r @"FAKE/tools/FakeLib.dll" #load "build-helpers/iOS.fsx" open Fake Target
"ios-build" (fun () -> iOS.build "Debug|iPhoneSimulator" ) Target "ios-adhoc" (fun () -> iOS.build "AdHoc|iPhone" ) Target "ios-testflight" (fun () -> iOS.publishToTestFlight() ) "ios-adhoc" ==> "ios-testflight" RunTarget() TeamCityHelper.PublishArtifact "path/to/App.zip" TeamCityHelper.sendTeamCityNUnitImport "results.xml" Helpers
FAKE #r @"FAKE/tools/FakeLib.dll" #load "build-helpers/iOS.fsx" open Fake Target
"ios-build" (fun () -> iOS.build "Debug|iPhoneSimulator" ) Target "ios-adhoc" (fun () -> iOS.build "AdHoc|iPhone" ) Target "ios-testflight" (fun () -> iOS.publishToTestFlight() ) "ios-adhoc" ==> "ios-testflight" RunTarget() TeamCityHelper.PublishArtifact "path/to/App.zip" TeamCityHelper.sendTeamCityNUnitImport "results.xml" TestFlight(fun p -> {p with File: "path/to/App.app" Notes: "Now with 42% more awesome!" }) Helpers
FAKE #r @"FAKE/tools/FakeLib.dll" #load "build-helpers/iOS.fsx" open Fake Target
"ios-build" (fun () -> iOS.build "Debug|iPhoneSimulator" ) Target "ios-adhoc" (fun () -> iOS.build "AdHoc|iPhone" ) Target "ios-testflight" (fun () -> iOS.publishToTestFlight() ) "ios-adhoc" ==> "ios-testflight" RunTarget() TeamCityHelper.PublishArtifact "path/to/App.zip" TeamCityHelper.sendTeamCityNUnitImport "results.xml" HipChatNotification(fun p -> {p with From = "App BuildBot" Message = "Published to TestFlight" Color = "green" }) TestFlight(fun p -> {p with File: "path/to/App.app" Notes: "Now with 42% more awesome!" }) Helpers
FAKE Helpers for Xamarin “path/to/MyApp.sln“ |> RestoreComponents (fun defaults ->
{defaults with ToolPath = “...” })
FAKE Helpers for Xamarin “path/to/MyApp.sln“ |> RestoreComponents (fun defaults ->
{defaults with ToolPath = “...” }) iOSBuild (fun defaults -> {defaults with ProjectPath = “path/to/MyApp.sln” Configuration = “AppStore” Target = “Build” })
FAKE Helpers for Xamarin iOSBuild (fun defaults -> {defaults with
ProjectPath = “path/to/MyApp.sln” Configuration = “AppStore” Target = “Build” }) “path/to/MyApp.sln“ |> RestoreComponents (fun defaults -> {defaults with ToolPath = “...” }) AndroidPackage (fun defaults -> {defaults with ProjectPath = “path/to/MyApp.csproj” }) |> AndroidSignAndAlign (fun defaults -> {defaults with KeystorePath = “...” KeystorePassword = “...” KeystoreAlias = “...” }) |> fun file -> TeamCityHelper.PublishArtifact file.FullName
How We Work At
None
None
None
Git / GitHub ▪ Feature branches ▪ Every app builds
on every branch ▪ Any branch can be pushed to TestFlight ▪ Pull Requests for code review
Test-Driven Core
UI Tests and Test Cloud
Deployment and Distribution
Deployment and Distribution
Deployment and Distribution
Continuous Monitoring
Demo github.com/gshackles/xamarin-ci-sample
Questions? @gshackles
[email protected]
! github.com/gshackles speakerdeck.com/u/gshackles