List of Figures

Chapter 1. Introducing native cross-platform applications with Xamarin

Figure 1.1. A comparison of the different mobile-development platforms

Figure 1.2. Vendor-specific apps use the same language for all layers but different languages on each platform

Figure 1.3. Cordova apps: HTML/CSS/JavaScript for the UI and business logic wrapped into an app by the Cordova framework.

Figure 1.4. Xamarin apps are written in C#, so you can share common business logic and also have platform-specific UIs.

Figure 1.5. Xamarin.iOS uses an ahead-of-time compiler.

Figure 1.6. Xamarin Android uses a Just-in-time compiler and a Mono runtime.

Figure 1.7. Xamarin.Forms apps have a cross-platform UI to share even more code.

Figure 1.8. Visual Studio can connect to a Mac locally or in the cloud to build and debug iOS apps in a simulator.

Figure 1.9. The mobile-optimized development lifecycle is a continuously iterating cycle of develop, test, build, distribute, and monitor.

Figure 1.10. Mocking is a simple technique to allow you to unit test without worrying about dependencies.

Figure 1.11. A summary of all the steps for each cycle of a production app

Chapter 2. Hello MVVM—creating a simple cross-platform app using MVVM

Figure 2.1. A simple square-root calculator app that calculates the square root of a given number

Figure 2.2. Xamarin apps are written in C# so you can share any common business logic while having a platform-specific UI.

Figure 2.3. To maximize code reuse, it would be good to have UI logic in shared code.

Figure 2.4. MVVM has a model, a view model, a view, and a binding layer that keeps the view and view model in sync and connects events on the view to the view model.

Figure 2.5. Binding keeps the value on the view in sync with the value in the view model.

Figure 2.6. The different layers of MVVM fit with the different layers of a Xamarin app.

Figure 2.7. The cross-platform layers in a mobile app are implemented in .NET Standard libraries.

Figure 2.8. A typical cross-platform app would contain a .NET Standard library with the core code, an Android app with Android-specific code, and an iOS app with iOS-specific code

Figure 2.9. Selecting the MvvmCross Template Pack from the Visual Studio extension manager

Figure 2.10. The New Solution dialog boxes showing the MvvmCross cross-platform app solution template, and setting the project name

Figure 2.11. The three projects that are created for you in the new solution

Figure 2.12. Selecting the MvvmCross for Visual Studio extension from the Visual Studio Extension manager

Figure 2.13. The New Project dialog box, where you can create your new solution

Figure 2.14. The three projects left in the solution after deleting the unwanted ones

Figure 2.15. The structure of the cross-platform core project

Figure 2.16. The structure of the iOS and Android app projects

Figure 2.17. Our Hello Cross-Platform World apps running on both Android and iOS

Figure 2.18. The Android device selection menus

Figure 2.19. The iOS device selection menus

Figure 2.20. The structure of the core project showing the location of the FirstViewModel class

Figure 2.21. Both sample apps showing the new text, changed by changing only one line of code

Figure 2.22. Our UI code is in the platform-specific UI layer; our core class with its string property is in the cross-platform business logic layer.

Chapter 3. MVVM—the model-view–view model design pattern

Figure 3.1. A simple square-root calculator app that calculates the square root of a given number

Figure 3.2. A typical user interaction with our square-root calculator

Figure 3.3. The model layer with the classes for the calculator app

Figure 3.4. The view-model classes for the calculator app, with a view model that wraps the SquareRootCalculator

Figure 3.5. The view model is a representation of the state shown in the model.

Figure 3.6. The binding listens to changes in the view model and updates the view accordingly.

Figure 3.7. Collections can be bound to list controls, and when the collection changes, the list control on the UI is updated.

Figure 3.8. When an observable collection is updated, an event is raised and the binding detects this and tells the UI to update.

Figure 3.9. Commanding a genie to bring you coffee. It would have been eternal wealth, but coffee was easier to draw.

Figure 3.10. Our genie is like the ICommand interface—we can make a wish (Execute) and see when we’ve run out of wishes (CanExecuteChanged).

Figure 3.11. We can also ask the genie if we can have any more wishes (CanExecute).

Figure 3.12. Events such as button clicks can be bound to commands, and these commands are executed when the event is raised.

Figure 3.13. The view layer is not cross-platform so the views have to be created twice.

Figure 3.14. Binding connects the view and view model together in a loosely coupled way, but it needs to be platform-specific to know which properties and events in the view layer to use.

Figure 3.15. Value converters allow you to convert a value from the view model to a type that the view is expecting.

Figure 3.16. Navigating from one screen to another by tapping on a name in the people list

Figure 3.17. View-first navigation—the view drives the creation of view models and navigates to other views.

Figure 3.18. View-model–first navigation—the view model drives the creation of views using the MVVM framework and navigates to other view models.

Figure 3.19. The complete square-root calculator, showing the interactions between all the layers of MVVM

Chapter 4. Hello again, MVVM—understanding and enhancing our simple MVVM app

Figure 4.1. The structure of the core project showing the location of the FirstViewModel class

Figure 4.2. The cross-platform application layer code lives in App.cs in the core project.

Figure 4.3. The structure of the Android app project showing the location of the FirstView.axml layout file

Figure 4.4. The FirstView.axml in the designer view

Figure 4.5. The FirstView.axml in the source view

Figure 4.6. Binding detects the event on the view and updates the view model, and it detects events on the view model and updates the view.

Figure 4.7. The views in iOS live in the Views folder with a view controller called FirstView and a storyboard called FirstView.storyboard.

Figure 4.8. The iOS storyboard has two controls: one called Label and one called TextField.

Figure 4.9. Using bait and switch with a text-to-speech plugin to compile against a .NET Standard version and then use the platform-specific code at runtime

Figure 4.10. Adding the TextToSpeech plugin to all projects from the NuGet package manager

Figure 4.11. Adding the TextToSpeech plugin to a single project from the Visual Studio for Mac Add Packages dialog box

Figure 4.12. To make coffee at home, you need to control everything.

Figure 4.13. At a coffee shop, you give up control of coffee-making

Figure 4.14. The magic box that is an IoC container—you tell it what types you have, and when you ask for an instance of a type, any dependencies are resolved and then injected into the constructor of the type you’ve requested.

Figure 4.15. The exception thrown when MvvmCross can’t resolve a type from its IoC container

Figure 4.16. The structure of the layout folder inside the resources folder of the Android app project, showing the location of the FirstView.axml layout file

Figure 4.17. The new Android app with its Say Hello button

Figure 4.18. The structure of the Views folder in the iOS app project, showing the location of the FirstView storyboard

Figure 4.19. Dragging a button to the storyboard

Figure 4.20. The constraint handles for constraining the size, distance to other controls, and center alignment

Figure 4.21. The three steps to set up the constraints—set the top constraint, the width constraint, and the horizontal center constraint.

Figure 4.22. Lay out the constraints and click the Update Frames to Match Constraints button to see what the view will look like at runtime.

Figure 4.23. The constraints showing in the Properties pad

Figure 4.24. Setting the widget properties for the button

Chapter 5. What are we (a)waiting for? An introduction to multithreading for Xamarin apps

Figure 5.1. Apps performing operations in the background, such as loading data, usually have some kind of indicator showing that something’s happening.

Figure 5.2. On Android, if an app blocks for a long time, the user is told and given a choice of waiting for it to be responsive again, or closing it.

Figure 5.3. When you’re waiting for a large coffee order in a badly run coffee shop, you might just give up before you get your coffee.

Figure 5.4. Ordering one coffee at a time and having it made, then ordering another takes a long time.

Figure 5.5. If you can place your coffee order up front, you’re free to do other stuff while it’s being made.

Figure 5.6. Having two baristas means that one can take orders while the other makes coffee.

Figure 5.7. Having multiple baristas to make coffee means the orders can be made more quickly.

Figure 5.8. In an email app there will be a UI thread that keeps the UI responsive and a background thread to download emails.

Figure 5.9. The UI thread handles input from the user sequentially, so it has to finish handling one input before it can handle another.

Figure 5.10. The UI thread handles messages from the OS resulting from user interactions, and if it takes too long to handle a message, the UI appears unresponsive.

Figure 5.11. When you order coffee from the server, they give the baristas different tasks to do, such as making a latte or a flat white.

Figure 5.12. The task scheduler takes tasks and runs them on the appropriate thread.

Figure 5.13. Running a task executes its code on a background thread.

Figure 5.14. Tasks can be chained, such as asking a dishwasher to bring more cups and then fetch more coffee beans.

Figure 5.15. Tasks can be continuously polled to see if they’ve finished.

Figure 5.16. Waiting on a task blocks until the task has finished

Figure 5.17. Continuations are a good way to handle the result of a task because they run after the task is complete and have access to the result of the original task.

Figure 5.18. Only one server interacts with customers: they hand off tasks to baristas who make coffee and then take back control to hand the coffee to the customer.

Figure 5.19. Updating the iOS UI from a background thread gives a thread-access exception.

Figure 5.20. Continuations can be run on any task scheduler, so they can be set to run back on the UI thread.

Figure 5.21. When a property-changed event is detected, the binding layer will marshal the call to update the UI onto the UI thread automatically.

Figure 5.22. Timeline of the ViewDidLoad method: the delay method starts, the delay task is created and started on a background thread, the UI is updated, and the method ends.

Figure 5.23. If you await the delay task, the ViewDidLoad method finishes as soon as the await is called, with the remainder of the method being called in a continuation back on the original thread.

Figure 5.24. If your app looks like it’s doing something during a long operation, the user will be happier than if your app looks unresponsive.

Chapter 6. Designing MVVM cross-platform apps

Figure 6.1. Apps like Facebook look and work differently on iOS and Android.

Figure 6.2. Using out-of-the-box controls ensures your app will have a consistent look and feel with the rest of the OS.

Figure 6.3. Android and iOS have different paradigms for the most popular action a user might do—iOS uses toolbar buttons, whereas Android favors the floating action button.

Figure 6.4. The SquareRt app is pretty simple, with only one flow that the user can take.

Figure 6.5. Some possible UIs for SquareRt, a simple square root calculation app

Figure 6.6. Our final UI for the SquareRt app

Figure 6.7. The user flows for the Countr app—showing, adding, deleting, and incrementing counters

Figure 6.8. iOS and Android UIs for the Countr app with different UI conventions on each platform, such as an Add button in the toolbar on iOS, but a FAB on Android

Figure 6.9. The steps for showing counters—the user wants to see them, the app loads them, the app displays them to the user.

Figure 6.10. MVVM has three layers, with the view layer being platform-specific and the view-model and model layers being cross-platform.

Figure 6.11. User flows can map to the MVVM layers, with user interactions spanning the view and view-model layers.

Figure 6.12. Once you’ve mapped user flows to the MVVM layers, you can map classes to these as well.

Figure 6.13. Mapping showing and adding counters to the view, view-model, and model layers

Figure 6.14. Mapping incrementing and deleting counters to the view, view-model, and model layers

Figure 6.15. The Countr app maps to a set of view, view-model, and model layer classes.

Figure 6.16. If your code involves the UI, it needs to run on the UI thread, but if it uses external resources or is slow, it should run on a background thread.

Figure 6.17. The SquareRt app doesn’t do anything that needs to run in a background thread.

Figure 6.18. The Countr app needs to access storage, so it’s better to do this on a background thread before coming back to the UI thread to display the results.

Figure 6.19. To help work out which layer or thread to use, try mapping your user flows on this diagram.

Figure 6.20. The Android Manifest file in the Solution Pad and in the editor

Figure 6.21. The iOS info.plist file in the Solution Pad and the editor

Figure 6.22. iOS users upgrade often, with 79% of users being on the latest iOS version two months after launch.

Figure 6.23. Android users don’t (or can’t) upgrade as often as iOS users, with 1% being on the latest Android version two months after launch.

Figure 6.24. The SDK to compile against can be chosen from the Project Options.

Figure 6.25. The Android manifest editor

Figure 6.26. The Visual Studio Android properties

Figure 6.27. Setting the target Android device

Figure 6.28. The Deployment Target can be set in the info.plist file.

Figure 6.29. Xcode can download and install older versions of the simulator, but only recent versions are available.

Figure 6.30. The linker strips out any code that’s not explicitly used.

Figure 6.31. The Android linker settings

Figure 6.32. Linker settings, showing the options

Figure 6.33. The iOS linker settings

Figure 6.34. MvvmCross provides a class that prevents certain methods, properties, and events from being stripped out by the linker.

Chapter 7. Building cross-platform models

Figure 7.1. The model layer in an MVVM-based mobile app is written using cross-platform code.

Figure 7.2. The user flow for SquareRt that we mapped to classes in chapter 6

Figure 7.3. Adding the SquareRtCalculator class in Visual Studio for Mac (left) and Windows (right)

Figure 7.4. Using an IoC container to pass instances of ISquareRtCalculator wherever they’re needed

Figure 7.5. Adding a new NUnit library project

Figure 7.6. Adding a reference to another project

Figure 7.7. Adding the NUnit 3 extension to Visual Studio. You can also add the NUnit 2 extension to support NUnit projects created by Visual Studio for Mac.

Figure 7.8. Creating a new class library project to put our NUnit tests into

Figure 7.9. Install the NUnit package into your test project.

Figure 7.10. Adding a reference to the SquareRt.Core project from the SquareRt.Core.Tests project

Figure 7.11. Test fixtures can contain multiple tests, with setup run before each test, and tear down run after.

Figure 7.12. To run unit tests from inside the code editor, an option in the preferences needs to be set.

Figure 7.13. Unit tests can be run using the circles next to the test classes or methods.

Figure 7.14. Visual Studio can run tests in Text Explorer.

Figure 7.15. The user flows for the Countr app: showing, adding, deleting, and incrementing counters

Figure 7.16. The counters view talks to the view model, which in turn talks to the service, which talks to the repository, which stores and retrieves data from a database.

Figure 7.17. The best ORM is SQLite-Net-PCL, but there are a number of NuGet packages available with SQLite in the name, so be sure to install the correct one with the correct version.

Figure 7.18. The PCLStorage NuGet package gives access to the filesystem from .NET Standard libraries.

Figure 7.19. The layers in the Countr app

Figure 7.20. Mocking is a simple technique allowing you to unit-test without worrying about dependencies.

Figure 7.21. Installing the Moq NuGet package gives you a simple way to mock interfaces in your unit tests.

Figure 7.22. REST APIs allow you to send requests to URLs using HTTP verbs, and to get data back.

Figure 7.23. Configuring the new Bing search API resource

Figure 7.24. The Microsoft cognitive service APIs use API keys to control access.

Figure 7.25. Overview of the JSON document returned from the Bing search service

Figure 7.26. Adding the Newtonsoft.Json NuGet package

Figure 7.27. The JSON properties are mapped to the properties of C# classes based on their names.

Figure 7.28. HTTP requests can be suffixed with a ? followed by query parameters as multiple key=value pairs separated by an &.

Chapter 8. Building cross-platform view models

Figure 8.1. The view-model layer in an MVVM-based mobile app is written using cross-platform code.

Figure 8.2. The only user flow in SquareRt, and the view, view-model, and calculator classes that you need to implement it

Figure 8.3. The state that will be represented by the view model

Figure 8.4. The behavior that the view model will need to implement

Figure 8.5. The user flows for the counter app—showing, adding, deleting, and incrementing counters

Figure 8.6. The Countr app maps to a set of views, view models, and model-layer classes.

Figure 8.7. Master/detail apps have a master list in one view and a detail view for seeing, editing, or creating an individual item.

Figure 8.8. The Countr app has a list of counters and a detail screen to add a new counter.

Figure 8.9. The state that will be represented by the two view models: a master view model and a detail view model

Figure 8.10. The behavior for the master and detail view models

Figure 8.11. Value conversion inside a property

Figure 8.12. Adding the Moq NuGet package to the unit-test project

Figure 8.13. Adding the MvvmCross NuGet package to the unit-test project

Figure 8.14. MvvmCross view models raise property-changed events using a dispatcher.

Figure 8.15. Using a value converter to convert properties

Figure 8.16. The counter view model has two uses—it’s an item in the list of counters, and it’s the view model for the add-new-counter screen.

Figure 8.17. Collections can be bound to list controls, and when the collection changes, the list control on the UI is updated.

Figure 8.18. You can load counters on a background thread, but you need to show them on the UI thread.

Figure 8.19. The first user flow in Countr, loading and showing counters, is implemented by the LoadCounters method on the view model.

Figure 8.20. The second user flow in Countr, incrementing a counter

Figure 8.21. The counters service increments a counter by first incrementing the value and then saving the newly incremented value.

Figure 8.22. The third user flow in Countr, deleting a counter

Figure 8.23. A messenger allows different components of an app to publish or subscribe to messages.

Figure 8.24. Using a messenger to send messages from the counters service to the counters view model when the list of counters changes

Figure 8.25. Adding the MvvmCross Messenger plugin NuGet package to the Countr.Core project

Figure 8.26. Navigation is like sheets of paper being stacked up and unstacked.

Figure 8.27. The final user flow in Countr, adding a new a counter

Chapter 9. Building simple Android views

Figure 9.1. The view layer in an MVVM app is written in platform-specific code.

Figure 9.2. The UI for the SquareRt app

Figure 9.3. Use material such as a stack of paper as a metaphor for your design.

Figure 9.4. A distinct floating action button is a clear way to indicate a popular user action.

Figure 9.5. Screen objects should move like real objects to help users feel comfortable with them.

Figure 9.6. The Designer can be used to visually position and configure the views and view groups in your layout.

Figure 9.7. Android UIs are a hierarchy of view groups and views.

Figure 9.8. Linear layouts lay out their child views in a line, either vertically (left) or horizontally (right).

Figure 9.9. Relative layouts lay out their child views based on layout rules.

Figure 9.10. Use different views to provide different controls for users to interact with.

Figure 9.11. The layout of the views and view groups in the SquareRt UI

Figure 9.12. Android supports multiple device densities, so to make things look the same on devices with different densities, you can size them using density-independent pixels.

Figure 9.13. The hierarchy of views and view groups in our layout

Figure 9.14. The basic layout for the view showing the toolbar

Figure 9.15. The resource browser can be used to find and select resource references.

Figure 9.16. The app with the ImageView centered in the area below the toolbar

Figure 9.17. Drag the Number text field over the top of the image.

Figure 9.18. Drag the Number text field to the relative layout using the document outline.

Figure 9.19. The alignments you need to lay out the EditText control in the right position relative to the image

Figure 9.20. Each activity goes through a lifecycle as it’s shown, hidden, reshown, or destroyed.

Figure 9.21. The working SquareRt app

Chapter 10. Building more advanced Android views

Figure 10.1. The UI for Countr

Figure 10.2. The layout of the views and view groups in the master Countr UI

Figure 10.3. Recycler views reuse views that are scrolled out of the visible part of the screen to save on creating views.

Figure 10.4. The layout of the views and view groups for each item in the recycler view

Figure 10.5. The layout of the views and view groups in the detail counter UI

Figure 10.6. The fully working Countr app

Figure 10.7. The app’s icon can be configured from the application manifest.

Figure 10.8. The launch screen shows a black screen with white text for a few seconds (left) before showing the “Loading...” text (right).

Figure 10.9. When your app starts up, it loads the splash screen activity marked as the main launcher, and this initializes MvvmCross before loading a layout.

Figure 10.10. When activities are shown, they’re drawn using their theme. This happens before the activity lifecycle is run, OnCreate is called, and layouts are loaded.

Figure 10.11. The layout of the splash screen XML drawable

Figure 10.12. Some of the standard named colors used in an Android app

Chapter 11. Building simple iOS views

Figure 11.1. The view layer in an MVVM app is written in platform-specific code.

Figure 11.2. The UI for the SquareRt app

Figure 11.3. A clear image can summarize content and not distract from it.

Figure 11.4. Lots of negative space (or whitespace) can enhance clarity by helping to reduce clutter.

Figure 11.5. Zooming from one level to another shows a natural hierarchy.

Figure 11.6. Storyboards can contain multiple view controllers, and each view controller has a single view inside it that can contain one or more controls, as well as a backing class.

Figure 11.7. The storyboard designer in Visual Studio showing two view controllers

Figure 11.8. Some of the controls available to iOS developers

Figure 11.9. iPhones and iPads have different screen resolutions.

Figure 11.10. Retina devices have double the pixel resolution of non-retina devices.

Figure 11.11. Orchestras are laid out relative to the conductor.

Figure 11.12. Positioning using explicit values leads to bad layouts when changing screen sizes or orientations.

Figure 11.13. Constraints can be used to set the width, height, left, right, top, bottom, and centers.

Figure 11.14. A button positioned 20 points below a label

Figure 11.15. The constraint equation for putting a button 20 points below a label

Figure 11.16. @2x images are twice the resolution, but they’re the same size on screen.

Figure 11.17. If no @2x image is available, images are rendered at twice the pixel size on retina devices, with one image pixel taking up 4 pixels on screen.

Figure 11.18. Asset catalogs make organizing your images easier. They can include images for all resolutions of iPhones and iPads or images that work on both.

Figure 11.19. Adding a new storyboard

Figure 11.20. Adding a new view controller to a storyboard

Figure 11.21. Asset catalogs are shown as a special folder in your iOS project.

Figure 11.22. New image sets are added from the asset catalog, and images can be added to each image set for the different resolutions.

Figure 11.23. Constraint handles for constraining the size, distance to other controls, and center alignment

Figure 11.24. To create the center constraints, first drag the center constraint handle and drop it on the horizontal dashed guideline. Then drag and drop it onto the vertical one.

Figure 11.25. Constraints are visible in the Layout tab of the Properties pad, or in the Document Outline pad.

Figure 11.26. Constraints can be selected from the Layout tab of the Properties pad (or by double-clicking the Document Outline pad), and their properties can be edited in the Properties pad.

Figure 11.27. Once the constraints are set, you can update the designer to show what the UI will look like at runtime.

Figure 11.28. Setting the properties for the text field from the Properties pad

Figure 11.29. The constraints to position the text field, relative to the image

Figure 11.30. Set the constraints by dragging the T-bar handles to the dashed lines displaying the edges of the image view.

Figure 11.31. The constraints for the text field

Figure 11.32. The constraints for the result label

Figure 11.33. The SquareRt view on an iPhone 4s, iPhone 6, and iPad

Figure 11.34. The iOS Photos app has a different UI for landscape and portrait orientations.

Figure 11.35. The installed size classes for a view

Figure 11.36. UIs sometimes need to be laid out differently to look good in different orientations.

Figure 11.37. Configuring constraints to only be installed for specific size classes

Figure 11.38. The lifecycle of a view controller from being created and loading the view to closing the view controller and unloading the view.

Figure 11.39. The backing class and storyboard ID needs to be set on the view controller in your storyboard.

Figure 11.40. Setting the name on the controls adds a property with that name to the designer file.

Figure 11.41. SquareRt running on an iPhone in portrait and landscape, and on an iPad

Chapter 12. Building more advanced iOS views

Figure 12.1. The UI for Countr

Figure 12.2. Table views can have multiple named cell types, and they’ll reuse cells of the right types as needed.

Figure 12.3. The prototype cell for a counter containing two labels and a button, laid out with one label on the left of the cell, the button on the right, and the second label to the left of the button

Figure 12.4. Navigation controllers are a type of container view controller that provides navigation between other view controllers.

Figure 12.5. Out of the box, iOS handles navigating forwards and backwards, including updating the navigation bar to show the previous page name.

Figure 12.6. Navigation bars have buttons on the left and right with a title in the middle.

Figure 12.7. The properties and constraints for the counter name text field

Figure 12.8. The fully working Countr app

Figure 12.9. iOS supports a huge range of app icon sizes for different devices, uses, and OS versions. These are the possible icons for iOS devices; you can also configure different icons for Apple Watch apps.

Figure 12.10. The application lifecycle starts by showing the launch screen. Then the app delegate methods are called, and this loads the first view.

Figure 12.11. Creating a launch screen with a dark gray background and an image in the center

Chapter 13. Running mobile apps on physical devices

Figure 13.1. Tap the build number seven times to enable developer mode.

Figure 13.2. Turn on USB debugging and tap OK at the prompt.

Figure 13.3. Once USB debugging is turned on, you need to allow individual computers to connect and debug.

Figure 13.4. When you have a device configured and plugged in, you can select it for debugging.

Figure 13.5. Android APKs can be managed from the Archive Manager.

Figure 13.6. Selecting the distribution channel

Figure 13.7. Creating a keystore file involves giving it a name, a password, and one piece of personal information.

Figure 13.8. Provisioning profiles aren’t the most popular thing with developers...

Figure 13.9. The bundle identifier is set in the info.plist file.

Figure 13.10. Create a new iOS Single View app with a bundle identifier that matches your Xamarin app.

Figure 13.11. Xcode needs a valid Apple ID to create profiles, and it will automatically create a default team for you from your Apple ID.

Figure 13.12. Once your device is plugged in, select it from the drop-down in the top left.

Figure 13.13. The first time you install an app using a provisioning profile from Xcode, you need to trust it.

Figure 13.14. You can manage iOS certificates from Xcode.

Figure 13.15. You can add an Apple Developer account from the Visual Studio for Mac preferences.

Figure 13.16. Visual Studio for Mac can be used to create new certificates.

Figure 13.17. You can also manage iOS certificates from the Apple Developer portal.

Figure 13.18. App IDs are created from the Apple Developer portal (some parts of the form have been removed to save space).

Figure 13.19. You can find device identifiers for plugged-in devices using Xcode.

Figure 13.20. From the Apple Developer portal you can register individual devices or upload a file with multiple devices.

Figure 13.21. After creating a provisioning profile, you can download and install it from the Developer portal.

Figure 13.22. Provisioning profiles can be downloaded and installed from Xcode or Visual Studio for Mac.

Figure 13.23. You can change the Provisioning Profile in the iOS bundle settings of the project properties, but it’s best left on Automatic.

Chapter 14. Testing mobile apps using Xamarin UITest

Figure 14.1. UI tests, like unit tests, follow the arrange, act, assert pattern.

Figure 14.2. Adding a new UITest project using Visual Studio for Mac (left) and Windows (right)

Figure 14.3. Adding the internet permission to AndroidManifest.xml

Figure 14.4. Adding the Xamarin Test Cloud Agent NuGet package

Figure 14.5. The Test Explorer (Windows) and Test pad (Mac)

Figure 14.6. Grouping tests in the Visual Studio Test Explorer

Figure 14.7. Installing the NUnit 2 test adapter

Figure 14.8. The device to test on is set in the same way as the device for debugging.

Figure 14.9. The visual tree on Android and how it maps to the UI

Figure 14.10. The REPL running in a command-line window

Figure 14.11. The visual tree for Countr on iOS inside the REPL

Figure 14.12. The visual tree for Countr on Android in the REPL

Figure 14.13. Querying by ID returns only those items in the tree that match the ID.

Figure 14.14. Setting the Accessibility Identifier from a storyboard

Figure 14.15. Querying by ID and text returns only those items in the tree that match the ID and text.

Figure 14.16. The output of a test failure, showing that the query for “new_counter_name” didn’t give any results

Chapter 15. Using App Center to build, test, and monitor apps

Figure 15.1. The mobile-optimized development lifecycle is a continuously iterating cycle of develop, test, build, distribute, and monitor.

Figure 15.2. Visual Studio App Center—Mission Control for apps

Figure 15.3. Setting up your app in App Center

Figure 15.4. To create a build, you first need to connect App Center to your source code repository.

Figure 15.5. App Center can build your branch, as well as sign it, test it, and set it up for distribution.

Figure 15.6. All builds for a branch can be seen by clicking on the branch.

Figure 15.7. Your Android app should build successfully.

Figure 15.8. iOS builds have a few more options than Android builds.

Figure 15.9. Use Keychain Access to export your certificate.

Figure 15.10. You can download the packaged build from App Center.

Figure 15.11. To create an IPA file with every build, turn on Build iTunes Package Archive.

Figure 15.12. Selecting the devices to test on

Figure 15.13. Configuring the test series and testing framework

Figure 15.14. The last panel shows commands to run to execute the test series.

Figure 15.15. The App Center CLI uploads your binaries, validates them, and then runs the tests on the selected devices.

Figure 15.16. The Test dashboard gives an overview of all your tests runs for your app.

Figure 15.17. The Test dashboard, giving an overview of the latest test run

Figure 15.18. The Test Cloud dashboard showing a failing test

Figure 15.19. The details of a test run

Figure 15.20. For each test you can see a screenshot from an individual device, as well as device metrics.

Figure 15.21. Adding the App Center NuGet packages

Figure 15.22. Active users shows how many unique users use your app each day.

Figure 15.23. Engagement can show you how many times each user uses your app, and for how long.

Figure 15.24. Devices gives a breakdown by device type and OS.

Figure 15.25. Breakdown by country and language

Figure 15.26. Versions breaks down your app usage by app version.

Figure 15.27. App Center shows you all events, including the total count and for how many users this event was tracked.

Figure 15.28. You can see the number of users who raised an event, and the total number of times the event was raised.

Figure 15.29. For events with properties, you can see the number of times the event was raised with specific values.

Figure 15.30. The Crashes tab shows crash-free users per day and a list of the crashes received.

Figure 15.31. Crash groups show details on affected users and the stack trace of the crash.

Chapter 16. Deploying apps to beta testers and the stores

Figure 16.1. You add and configure app collaborators from the Settings tab.

Figure 16.2. Allow apps to be installed from unknown sources.

Figure 16.3. Add distribution groups to allow you to distribute different builds of your app to different users.

Figure 16.4. Distribution can be configured on each branch.

Figure 16.5. After each build, users will get an email with a link to download and install your app from App Center.

Figure 16.6. To distribute your app manually, you start by uploading the APK.

Figure 16.7. Manage releases from the Releases section of the Distribute tab.

Figure 16.8. When you launch your app for the first time, it will connect to App Center to enable in-app updates.

Figure 16.9. To indicate that a new version of your Android app is available, increment the version number in the manifest.

Figure 16.10. Upon launching your app after an update has been distributed, you’ll be asked if you want to update.

Figure 16.11. Click the Publish an Android App button to create a new app on the Play Store and then enter the app’s name.

Figure 16.12. Once your app is ready to publish, the top banner will update to show this.

Figure 16.13. After reviewing your release, you can roll it out to the store.

Figure 16.14. Once your app has been reviewed, it will appear on the Play store.

Figure 16.15. Ideally you want to aim for a 5-star rating to get more downloads.

Figure 16.16. You can get device UDIDs from the Devices window in Xcode.

Figure 16.17. You can get device UDIDs from the Device window in iTunes.

Figure 16.18. You can get device UDIDs from the macOS terminal using Instruments.

Figure 16.19. Before you can install a beta build from App Center, install the App Center distribution profile.

Figure 16.20. Once the App Center profile is installed, you can install the app on your device.

Figure 16.21. Adding the App Center URL schema to the info.plist

Figure 16.22. The first time your app starts, it will enable in-app updates.

Figure 16.23. For your app to detect an update, either the build or version needs to be incremented.

Figure 16.24. When you launch your app after an update is available, you’ll be prompted to install the update.

Figure 16.25. iTunes Connect is used to manage all apps released to the Apple App Stores.

Figure 16.26. To create a new app, enter the name and bundle ID.

Figure 16.27. Application Loader is used to upload IPAs to Apple.

Figure 16.28. Apple is great at updating you about the progress of approving your app. There’s even an app to manage it, called Connect.

Figure 16.29. The Countr listing on the iOS App Store

Figure 16.30. Review ratings and reviews from users via the Activity tab.

Appendix A. UI flows and threads for SquareRt and Countr

Figure A.1. The SquareRt app is pretty simple, with only one flow that the user can take.

Figure A.2. The SquareRt user flow is trivial: the view handles the user interactions, the view model passes values straight through, and the model can calculate on the UI thread.

Figure A.3. The user flows for the Countr app: showing, adding, deleting, and incrementing counters

Figure A.4. The first user flow for Countr loads counters on a background thread and then updates the UI from the UI thread.

Figure A.5. Navigation to a new screen occurs on the UI thread in the view-model layer.

Figure A.6. Saving the counter happens in the model layer on a background thread.

Figure A.7. Once the counters have been updated, the view model loads the counters from storage via the model layer on a background thread, and then it updates the UI from the UI thread.

Figure A.8. Counters are deleted from storage on a background thread, the counters are reloaded on a background thread, and the UI is updated back on the UI thread.

Figure A.9. When a counter is updated, the updated counter is stored on a background thread and the UI is updated on the UI thread.

Appendix B. Using MVVM Light instead of MvvmCross

Figure B.1. The main storyboard needs to contain a navigation controller as the initial view controller, have the counters view as the root view controller in the navigation controller, and contain the counter view.

Figure B.2. The main interface needs to be set to your storyboard in the info.plist file.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.133.96