Category: AWS Mobile


React serverless starter application with one-click AWS deployment and hosting

Serverless applications are more popular every day. Many developers want to implement completely serverless hosted websites that are functionally equivalent to traditional infrastructures. However, with serverless websites, it’s often tricky to deal with registration, sign-in, and MFA flows. It can also be difficult to manage API routing, CORS settings, endpoint authorization, and user authentication. Hooking all of these features together with a hosting solution and global CDN takes extra time for features that are standard for business applications today.

We’ve recently been blogging about building applications with React and using them in conjunction with the Hosting and Streaming AWS Mobile Hub features. Today, we are announcing a couple of additions to this solution set.

First, we’ve enhanced the Cloud Logic functionality in a Mobile Hub project so that new projects launched via Import can include a custom AWS Lambda function. The import can also configure more settings such as CORS for Amazon API Gateway or Lambda environment variables.

Second we are releasing a ReactJS starter project on GitHub to demonstrate these capabilities. The sample can be run with a single click, using the new Deploy from GitHub button capabilities of Mobile Hub. After it is deployed, you can run the sample locally with a webpack server. You can also deploy it as an Amazon S3 hosted static site with an Amazon CloudFront origin. The sample is optimized for mobile devices, which enables you to view the app from your phone or desktop browser. You can register users in the system and log user in with SMS-based MFA. After they are signed in, users can insert sample data for “BBQ Restaurants” and view all restaurants in the system. They can then navigate to see everything on the menu and place an order. The sample also demonstrates using forgotten password workflows.

In the sample, the import functionality automatically configures the following:

  • Amazon Cognito User Pools and Federated Identities
  • Amazon API Gateway, AWS Lambda, and Amazon DynamoDB
  • Cross-origin resource sharing (CORS) for the API
  • IAM roles and policy for the Lambda execution role
  • IAM roles and policy for the user roles that access API routes after authentication

You can find the sample demonstrating this functionality here. The repository describes the steps to get the sample running, and describes how to use portions of the sample in your own application and customizations. In this blog post, we dive into a few details.

Prerequisites

To get the sample running quickly you need:

Installation

Clone the GitHub repository and use the Deploy to Mobile Hub button on the page.

After the deployment is complete, click Hosting and Streaming in the Mobile Hub console. At the bottom of the page, download the aws-exports.js file into the ./aws-mobile-react-sample/client/src/configuration folder of your cloned repo.

Use the following commands to run the application:


npm install
npm start

Walkthrough of the application

After the application is running you will see a page with a Login or SignUp Now button. Click SignUp Now to register a new user in the system.

An SMS confirmation code is sent to the phone number you provide. You must provide the phone number to complete the registration process. The confirmation code redirects you to the home screen, where you enter the username and password and then click Login.

You will recieve another confirmation code. This is the MFA code for logging in the user. Enter the code in the screen to complete the login process.

Now that you’re in the application, click Insert Restaurants to load data into the system. Behind the scenes, this invokes Amazon API Gateway, using the valid user credentials from Amazon Cognito. The API is configured to route the request to AWS Lambda, which is running Express using AWS Serverless Express. A route is configured to initialize data, which inserts sample data into Amazon DynamoDB.

Next click List Restaurants. The restaurants that were added into DynamoDB appear

Click any of the restaurants to see a menu. Place an order by clicking the Order button next to an item.

To see the current order, click Orders in the navigation bar. Two records display immediately and two other records display momentarily. This is to demonstrate persisting data in local storage for rendering versus returning a response from a network call.

You can also package and deploy the app by running:

npm run build

The build uses webpack to produce a bundle that can be uploaded to the S3 bucket created by the import. The output will be in ./aws-mobile-react-sample/client/build.

You can use the AWS CLI to upload the contents of this directory to the bucket. This process is described on GitHub. You can also use the Manage Files function in the Hosting and Streaming page of the Mobile Hub console.

After you upload the contents of the build directory, click either View from S3 or View from CloudFront to see your deployed erverless website.

Customization

The GitHub repository covers some advanced scenarios for modifying this sample or using pieces of it in your own React application. Some of these scenarios are as follows:

  • Using the registration and login components with Amazon Cognito for your application.
  • Using the REST client to make signed, authenticated requests to Amazon API Gatway.
  • Using the REST client to make unauthenticated requests to Amazon API Gateway or generic HTTP resources.
  • Modifying the Express routes in AWS Lambda to perform different operations against Amazon DynamoDB, and calling these routes from the client application.

You can also modify the import process to fit your needs and include this in your own GitHub repository with a one-click button. If you open the ./aws-mobile-react-sample/backend/import_mobilehub directory in the repository and unzip react-sample.zip, you will find the following:

  • lambda-archive.zip
  • mobile-hub-project.yml

The lambda-archive.zip is the pre-built Lambda function, which you can use on import. This must follow the Lambda deployment process described in the AWS Lambda Developer Guide. We also include these steps in the Advanced section of the repository.

If you edit mobile-hub-project.yml you’ll notice some other interesting things that are now available for you to configure with project imports.

UPLOADS

The uploads section determines the custom AWS Lambda function that you can provide during an import. In our sample we use lambda-archive.zip, which was created from the files in the ./aws-mobile-react-sample/backend/lambda directory. The YAML section should also specify the target bucket as follows:

uploads:
  - !com.amazonaws.mobilehub.v0.Upload
    fileName: lambda-archive.zip
    targetS3Bucket: deployments

CLOUD LOGIC

In the same YAML file, you’ll notice the cloudlogic section. This contains everything you need to configure a custom AWS Lambda function and related settings as well as setting up your Amazon API Gatway API. You can configure things such as enabling CORS on the API or only allowing authenticated and authorized users access to invoke the API. This sample YAML demonstrates using Amazon Cognito to access the Amazon API Gateway API and configuring environment variables for your custom AWS Lambda function. You’ll also see controls such as runtime for your NodeJS version and handler which is the name of the file entry point for your code.

You can use ___DYNAMIC_PREFIX___-statictext in the enviornment variables configuration. This is beneficial for resources such as Amazon DynamoDB tables, which are generated at the time of import, Mobile Hub performs the appropriate substitutions after resource creation.

The YAML section should look like the following:

features:
  cloudlogic: !com.amazonaws.mobilehub.v0.CloudLogic
    components:
      ReactSample: !com.amazonaws.mobilehub.v0.API
        attributes:
          name: ReactSample
          requires-signin: true
        paths:
          /items: !com.amazonaws.mobilehub.v0.Function
            name: ReactSample
            codeFilename: uploads/lambda-archive.zip
            handler: lambda.handler
            enableCORS: true
            runtime: nodejs6.10
            environment:
              MENU_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_menu_item
              ORDERS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_orders
              RESTAURANTS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_restaurants
          "/items/{proxy+}": !com.amazonaws.mobilehub.v0.Function
            name: ReactSample
            codeFilename: uploads/lambda-archive.zip
            handler: lambda.handler
            enableCORS: true
            runtime: nodejs6.10
            environment:
              MENU_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_menu_item
              ORDERS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_orders
              RESTAURANTS_TABLE_NAME: ___DYNAMIC_PREFIX___-bbq_restaurants

 

The Mobile Hub import process also prepopulates some Environment Variables in the Lambda configuration:

  • MOBILE_HUB_DYNAMIC_PREFIX
  • MOBILE_HUB_PROJECT_ID
  • MOBILE_HUB_PROJECT_NAME
  • MOBILE_HUB_PROJECT_REGION

As a usage example, you could re-write the Lambda code in the starter application to reference these like so:


const MENU_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_menu_item`;
const ORDERS_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_orders`;
const RESTAURANTS_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-bbq_restaurants `;

You could also use these prepopulated variables for other utility purposes.

Wrapping up

We’re excited to bring you these capabilities. We hope that they accelerate your next serverless website or React project using AWS. Let us know in the GitHub issues section of the repository if you have any feedback or requests.

Deploying an EmberJS mobile web application with Mobile Hub

This post was authored by Michael Labieniec, AWS Sr. Solutions Architect.

AWS Serverless Architecture

Ember.js is a popular open source JavaScript framework for developing rich, dynamic web applications. It supports dependancy injection model and has been a is a stable contender in the JavaScript community. Ember.js also ships with its own CLI which supports building, testing, and deploying your applications. The Ember CLI supports installing plugins and the bundling of those plugins within your application, it has a built in web server to serve your application locally.

AWS Mobile Hub is an AWS service that guides you through feature selection and configuration, it automatically provisions the AWS services required. Mobile Hub generates working code that helps you integrate the AWS SDK for JavaScript with your application in minutes. When using Mobile Hub to develop JavaScript-based applications, JavaScript configuration files as well as a sample web application are generated for you, and placed in your Amazon S3 bucket. These configuration files can then be copied directly to your application environment for use. The files can be continuously updated when your AWS environment changes via Mobile Hub. This is useful for developing JavaScript web applications because your AWS configuration can be dynamically updated by Mobile Hub and your application can immediately realize and support those updates when hosted in Amazon S3.

Mobile Hub will copy a new aws-config.js and aws-exports.js to the Amazon S3 bucket associated with your application after you update your configuration. In order to utilize these in your local development environment, you need to download them from your S3 bucket. The files will be copied to the root of the S3 bucket, which may require you to copy them elsewhere for your application to properly include them.

Amazon Cognito lets you add user sign-up and sign-in to your mobile and web applications. This sample application uses Cognito User Pools for user management and storage, and Amazon Cognito Federated Identities for authentication the user pool. The application then uses Amazon DynamoDB directly through the AWS SDK for JavaScript. The sample application uses a custom Ember.js Adapter to abstract the API logic and allow utilization of Ember.js Models.

First, clone the repository and install the dependencies:

git clone https://github.com/awslabs/aws-mobilehub-ember
cd aws-mobilehub-ember && npm install

Then, click the following button to import the MobileHub.zip file and create the AWS back-end:

Alternatively you can download the .zip file from the GitHub repository and from the Mobile Hub console click Import your project and drag and drop the .zip file to create a new project.

After the import is complete the AWS environment is ready. Click Hosting and Streaming, and then click Download aws-config.js file. Copy the aws-config.js file to the ./vendor/aws-config.js directory of your application.

You can also download the file with the AWS CLI. You first need to know the Amazon S3 hosting bucket. You can see the bucket name by going to Resources from within you Mobile Hub project. Then from within the root directory of your application project run:

aws s3 cp s3://your-hosting-bucket/aws-config.js ./vendor/aws-config.js

If you don’t already have the Ember CLI installed run the following:

npm install -g ember-cli

Now that the aws-config.js file is copied to your vendor directory, run the following:

ember serve

Your application should now be available at localhost:4200. If you ever change your AWS Mobile Hub configuration, simply cp the configuration file again and deploy.

To retrieve the generated S3 bucket name for the cli commands, navigate to your project in the Mobile Hub console, click Hosting and Streaming, and then click Manage Files. Note the bucket name at the top of the screen.

To deploy your web application to Amazon S3, run the following:

ember build 
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Your web application is now available at the web hosting URL of the Amazon S3 bucket that Mobile Hub generated. To view your application:

  1. Goto Mobile Hub and click Hosting and Streaming
  2. Click View from S3

After about a minute, the file changes you pushed propagate to the CloudFront distribution. You can click View from CloudFront and browse the site from a CDN for faster performance. You can force this refresh to happen immediately from the Hosting and Streaming page:

  1. Click Edit your CDN distribution
  2. Click the Invalidations tab
  3. Select Create Invalidation and enter an asterisk (*) to refresh all the content

After the process completes, click View from CloudFront in the Hosting and Streaming section of Mobile Hub.

Making changes

We detail the application architecture at the end of this blog post. You can change parts of the application to meet your needs. Each time you deploy the application you must build and copy to Amazon S3, as follows:

ember build
aws s3 cp --recursive ./dist s3://your-s3-hosting-bucket/

Then either wait for a CloudFront distribution refresh or force one with an invalidation.

Walking through the sample

The Ember sample is a TODO or “notes” application. It walks through functionality for registering user accounts into your application (including email confirmation), login and logout functionality, session information and saving notes to a database. To demonstrate, first select Create User to register a new user account in the system. Enter the following:

  1. Unique username
  2. Complex password
  3. Valid email address

This process registers a user in the system with Amazon Cognito User Pools. A registration confirmation code is sent to the email address. Type that code in the page and select Confirm Registration at the bottom. The workflow for this sample allows you to immediately press Login with the previously entered credentials to access the application.

In the main page create a new note by clicking the plus sign (+) in the lower right corner. Type a title for the note and some content. Click Save Note, your data is written to Amazon DynamoDB. These notes are secured where only the users who create them can read or edit them after logging in.

Select the user’s name in the upper right corner of the page. Here you see information about the user session, such as JWT token details from Amazon Cognito User Pools. This is a great place to store user-specific attributes that can be read-only or editable by the user. Click User Attributes on the left side to view your email address.

Application Anatomy

Now that the sample application is up and running we dive a little deeper and explain the structure of an Ember application. You can incorporate pieces of the sample into your own projects.

There are two types of initializers in Ember: application initializers and application instance initializers.

Application initializers while your application boots and have no access to internal services. The application initializer performs a dependency injection process to ensure that everything your application needs is setup before loading UI or user state. This is also great for security control and separation of concerns in your application architecture.

Application instance initializers run while the application instance itself loads. This provides a way to configure the initial state of the application and inject values into application services. For example you can customize the UI based on a theme for users and control state.

Application Initializers

This application uses both types of initializers. The initializers allow us to initialize the AWS SDK for JavaScript before the application instance loads. The instance initializer allows us to inject values into services. We also use the deferReadiness and advanceReadiness in the application initializer to defer loading of the application until we have temporary credentials for making AWS API calls. The main application initializer is located in the app/initializers directory, as follows:

app/initializers/aws.js

To generate an initilizer runember g initializer myInitializer. This creates a new initializer .js file named app/initializers/myInitializer.js. It also create a unit test in tests/unit/initializers/myInitializer.js.

The AWS initializer instantiates the AWS SDK using the variables that are instantiated in the configuration file that Mobile Hub generated. This file was copied from your Amazon S3 bucket. Then, the initializer checks if there is a current session with Amazon Cognito User Pools. It retrieves temporary SDK credentials. The initializer uses these credentials to make AWS API calls with the SDK. The initializer then registers values for the application to use, and finally advanceReadiness to continue loading the application instance.

The initializer determines if there is a logged in user with the Amazon Cognito Identity SDK (included in ./vendor/amazon-cognito). If a session exists, register the session credentials and JWT tokens on the application instance. These are injected by the instance initializer.

Application Instance Initializers

The instance initializer is located in the instance-initializers directory, as shown next:

app/instance-initializers/auth.js

When the instance initializer runs, it has access to application services, as well as access to any values we previously registered within the application initializer.

You can generate instance-initializers with the ember-cli using ember g instance-initializer myInstanceInitializer. This generates a myInstanceInitializer.js in the instance-initializers folder. It also generates a unit test in test/unit/instance-initializers.

The auth instance initializer first retrieves the values registered in the application initializer, as well as the service we have created (app/services/cognito.js). Ember services are referenced using the prefix “service:”. The application-registered values that we registered in the initializer are completely custom (for example “auth:session”). It then injects those dependencies into the applicable service within our instantiated application instance: in this case, our custom cognito service.

Application Components

Within this application we use a service, model, adapter, and serializer to abstract the AWS logic away from the presentation level logic. This allows us to work with data using ember models, while the application adapter and serializer hold AWS-specific back-end logic. This architecture allows us to potentially swap adapters that communicate with different back-ends, or to even load and serialize different types of data (for example JSON vs. XML responses). The serializer takes whatever is retrieved via the adapter and serializes it to a uniform format (based on the extended ember class) for our routes and components to use.

Models, Adapters, and Serializers

The note adapter in this application is specifically tied to the note model, and note serializer. Ember uses this file-level naming convention to determine which components work together. For example, the note model utilizes the note adapter and serializer if the similarly named .js files are found in app/serializers or app/adapters. You can also define an “application” adapter and serializer which serves as a catch-all for any model actions.

You can generate a model by running ember g model myModel, which does not generate an adapter or serializer. You can generate these with ember g serializer|adapter. As long as you name them appropriately, they will are used. Otherwise, the model uses an application adapter or serializer if you generated one.

Data is initially requested via the note route. This route provides the result from the adapters call, serialized, to the Ember component, which in this case is directly used within the view. This model.notes dataset is then sent into the ui-note-list component for use within the view component.

Components and Controllers

Components are custom elements that align with the W3C Custom Elements spec and contain de-coupled view logic.

Components can reference and call methods on the higher level component or controller that instantiated the component. This abstracts away the model or data level logic, making the component more dynamic and re-usable. Components should never work with models or data. They should work with specific view logic and the data that is provided to them, allowing the components to be more de-coupled and re-usable. Components can also work with services directly.

Components can be generated via the ember-cli ember g component myComponent. This creates an app/components/my-component.js logic file, and an app/templates/components/my-component.hbs view template. Since Ember components adhere to the W3C Custom Elements spec, they require a “-” in their name.

To learn more about developing with Ember, see Guides and Tutorials on the Ember website.

Wrapping up

Using the Hosting and Streaming features of Mobile Hub is a great way to quickly provision a fully functioning back-end for your mobile web application. The application includes end-to-end functionality, including user life-cycle and application state. Using the provided sample should help you get started with building an Ember application. You can make changes to this application and get your site running quickly. You can also use the sample and the Deploy from GitHub Button, like this repository shows, to fork this application and create your own version. Others can use your version to quickly spin up a fully functioning back-ends.

Questions or Comments?
Reach out to us on the AWS Mobile Development Forum.

Source Code and Issues on GitHub
github.com/awslabs/aws-mobilehub-ember

Take Your Chatbot Mobile!

With Amazon Lex, any developer can quickly and easily create a chatbot. With AWS Mobile Hub, the same developer can just as easily integrate the bot into a mobile app.

Want to take your bot mobile? Use the Mobile Hub conversational bots feature to create your own mobile bot or import an existing bot into your mobile app. You can build, test, and publish your mobile bot in minutes. No deep learning expertise needed.

How does integration work? Integrate your bot into a fully native mobile app by using a sample bot template or by importing an existing Amazon Lex chatbot into Mobile Hub. Mobile Hub generates a fully functional mobile iOS or Android app, integrated with your bot. The sample mobile app provides the option to interact with your bot with voice or text, and includes built-in authentication provided by Amazon Cognito.

How do I do it?
Here’s how simple it is:

  1. Use Amazon Lex to build a bot or choose from one of the sample bots in Mobile Hub.
  2. Import your bot into Mobile Hub using the conversational bots feature.
  3. Download the generated iOS/Android project code.
  4. Launch your mobile app and start a conversation!

Want to see how others have done it?

The Kelley Blue Book team created their voice-enabled mobile application using Amazon Lex and Mobile Hub. Their bot allows users to interact with their vehicle API using natural spoken language. A simple inquiry like, “Kelley Blue Book, can you tell me the trade-in value for my 2012 Honda Civic?” gets expert car advice from an industry-leading automotive company.

To learn more about The Kelley Blue Book Bot and building your own mobile chatbot, see the post on the AWS AI blog.

We can’t wait to see what you can build with AWS Mobile Hub and Amazon Lex!

Testing Mobile Apps: A Primer

Why should you test your mobile app?  A recent study showed that almost a quarter of users only use a mobile app once, and a shocking 95% abandon an app within the first month.  Some of the reasons that users abandon an app are due to content and engagement.  The biggest non-content reasons for abandonment are application crashes and security concerns.  No one can prevent all application crashes.  The mobile ecosystem is too broad and unpredictable to provide a 100% guarantee.  However, testing ensures that your mobile app has been stressed on as many devices as possible , which enables you to identify and fix bugs early.

Types of mobile testing

There are seven types of scenarios that you should consider when testing a client-server application such as a mobile app:

  • Unit testing
  • UI testing
  • Fuzz testing
  • Performance testing
  • End-to-end testing
  • Pre-production testing
  • Canary (post-production) testing

Tests are organized into test suites – sets of tests that together test the entire functionality of your app.  Let’s look at each of these types.

Unit testing

Unit testing tests individual parts of your code for correctness, usually using an automated test suite.  A good unit test assures you that the functionality that you are expecting out of the unit (your code; usually a single method) is correct.  A good unit test is:

  • Repeatable – you can run it several times and it produces the same result.
  • Fast – you don’t want it to interrupt the flow of your work.
  • Readable – you can understand what the test is doing.
  • Independent – you can run a single test from a suite.
  • Comprehensive – you have enough tests to test all the main cases and corner cases of inputs and cover all code paths.

A good unit test suite augments the developer documentation for your app. This helps new developers come up to speed by describing the functionality of specific methods.  When coupled with good code coverage, a unit test acts as a safeguard against regressions.  Unit tests are important for anything that does not produce a UI.  For example, consider a Notes app that has a set of notes stored in a SQLite database on a mobile device. For this app, there is a class that accesses the notes and a set of classes that implement the UI.  The class that accesses the notes has unit tests.

Each platform has its own unit testing framework:

Each of these frameworks supports all of the features you need to start testing, including support for async functionality (a common pattern in mobile apps).   Each testing framework has its own appearance, but in essence all testing frameworks operate the same.  You specify some inputs, call the method to test, and then verify that the output is what you expect it to be.

UI testing

UI testing takes a flow that the user might follow and ensures it produces the right output.  It can be done on real devices or on emulators and simulators.  Given the same state (including backing stores and starting point), the UI test always produces the same output.  A UI test can be considered similar to a unit test. The input to the test is the user clicks and the output of the test is the screen.  UI testing is more closely associated with the device than with the platform language.  There is a preferred testing framework and each framework has a test recorder. This enables you to record a UI flow on one device and then replay the test on many other devices.  The test recorder allows you to get productive quickly:

In addition, there are cross-platform UI test frameworks to consider, primarily Appium and Calabash.  With Appium, you can choose a language. This is useful if you are writing Ionic or React Native apps because you can use JavaScript as the testing language.  Calabash requires that the tests are written in Ruby.  Neither of these frameworks provide a recorder to aid in writing tests.  Both frameworks are open source projects.

Finally, AWS Device Farm has a feature called Explorer for Android apps.  This feature investigates your UI and finds things to interact with.  When it finds a control, it interacts with the control.  This feature works with login screens, allowing you to validate authenticated sessions as well.

Ionic and React Native perform UI testing against compiled code, so your UI tests should not include Ionic or React Native code.  Instead, you are testing how the app acts on a device.

Fuzz testing

Unit tests and UI tests are used to ensure that the expected output happens when the expected input is used.  However, apps are used by humans and humans don’t always do the expected thing.  For that case, you can introduce a random stream of events into your app and see what happens.  This is known as monkey testing or fuzz testing. It’s a stress test that simulates what happens when the user randomly presses the screen, for example.  This is similar to a UI test.  However, you don’t need to write any tests since random events are created.

It is also interesting to record a fuzz test run.  It can be replayed later to reproduce any issue found, verify that the issue was fixed, and to scale testing across more devices.  Fuzz testing takes off when you take testing to the cloud with AWS Device Farm, allowing you to test on many more devices than you may have access to.

Performance testing

Gather performance metrics while running the UI and fuzz tests to ensure that your application does not take up significant resources on the device.  Such performance metrics include:

  • Battery drain and energy usage.
  • Appropriate usage of the GPS and other features that drain battery.
  • Network bandwidth usage.
  • Memory usage.

This data can be gathered during development using a profiling tool such as the Android Monitor (built into Android Studio) or Instruments (built into XCode).  During this process, you can also use network shaping, which simulates lower bandwidth network connections (for example, 3G connections) or spotty Wi-Fi connections.  This enables you to experience adverse network conditions as your users would and ensure an appropriate user experience.  If you are developing a mobile game, you can also measure the FPS (frames per second) for your mobile game when the device is stressed (low memory or restricted network capabilities).

For performance testing during the test phase (and beyond), use application performance monitoring (APM) tools such as New Relic Mobile or Splunk MINT.

Integration (end-to-end) testing

After you test your mobile app in isolation, you test it with a mobile backend. This is generally known as integration testing or end-to-end testing.  Take the same UI and fuzz testing that we already described, and then recompile your code with the live cloud backend.  Many organizations produce a separate test environment for this purpose.

If you are upgrading the mobile app (rather than releasing a new app) and the upgrade involves an upgrade to the backend resources – the database schema or API responses – then you also should test the upgrade scenarios during integration testing.  Users do not upgrade their mobile apps immediately, so multiple versions of your app will use the same cloud backend resources (even if only the database is affected).

If you are using a third-party cloud service (for example, a Weather API), then make sure you check their rules for throttling.  Test failures can result if the third-party cloud service detects you are making too many API calls.

Pre-launch or pre-submission testing

You are just about to launch your app to the public.  You’ve done all the appropriate testing on the latest devices and OS versions.  Run the UI and fuzz tests on as wide a pool of devices as you possibly can.  There is one final test before submitting your app to the app store.  You want to test your app on as large a community of devices and OS combinations as you possibly can.

An enterprise usually has the luxury of dictating a support matrix of devices. If you are producing a mobile app for the general public, then the situation is a little more complex.  OpenSignal estimates that there are over 24,000 distinct Android devices in the world. Over 18,000 of these were used in the last year.  The statistics from Google indicate that API level 19 (which is a few years old at this point) has only reached 73% of consumers. The iOS device types are a little more limited – there are only a handful of models, and iOS devices tend to be kept up to date.  That’s still numerous device / OS combinations.

One option is to maintain a device farm of your own, buying one of each device.  However, that is expensive to buy and maintain. A better option is to rent the devices you need for the pre-production run and let someone else worry about maintaining the latest device and OS versions. AWS Device Farm helps with this problem as well, running your UI and fuzz tests across a wide variety of devices and charging only for what you use.

Canary (post-production) testing

After your app is in production, use a canary test to ensure that the mobile app and the backend are running harmoniously. A canary test is a set of UI tests that run using the same mobile app that you distributed to your users and using the same (production) services on the backend.

You can generate a (different, smaller) test suite for an individual (canary) user and run this test suite on AWS Device Farm on a schedule to implement canary testing.

Best practices in testing

You don’t need to run all tests all the time.  The following are some best practices:

  • Architect your application so that the mobile application and backend can be tested independently.  Compile your app with “stub” methods that simulate the cloud services.  Also, try mock cloud services with frameworks like Mockito (Android) or Cuckoo (Swift).
  • All changes to the code base of your mobile app or backend should include appropriate unit tests or UI tests to check the new functionality.
  • Run unit tests with every build and UI tests on an emulator or simulator before checking in your code change.
  • Run a complete set of UI and fuzz tests on a pre-defined set of the most popular devices for your users on a regular basis. It is ideal to do this as part of a continuous integration pipeline (for example, using Jenkins). At minimum, you should run these tests on a nightly basis.  Monitor for application crashes and test failures.
  • Run your UI tests on as many devices as possible at intervals throughout the development process. At minimum, run a full set of tests on as many devices as possible before release.  Any test failures or application crashes should generate bugs to be fixed by the engineers.
  • Include enough information in your bugs to reproduce the failure. Include the test case, device and OS combination, whether the test was against the cloud services or the stubs, and video or screen captures of the test failure.
  • Analyze the test results.  A single test failure is useful.  Knowing that the same error or crash occurred on a set of devices with a common characteristic is more useful to the developers who need to diagnose the problem.

AWS Device Farm is a mobile app testing service that lets you test and interact with your Android, iOS, and web apps on many devices at once. It enables you to capture video, screenshots, logs, and performance data to pinpoint and fix issues before shipping your app.  You can use it to automate a large portion of the suggested mobile app testing capabilities described in this article.

With these best practices, you are on your way to producing a quality product that can be enjoyed by the maximum number of users.

Integrate the AWS SDK for JavaScript into a React App

In our last blog post, I showed how to create a React app using the create-react-app tool provided by Facebook, and then deploy the app to a content delivery network driven by AWS Mobile Hub, Amazon S3, and Amazon CloudFront. This enables you to produce dynamic single page applications (SPAs) and serve them to a global audience.

Very few web apps are static web sites.  Ideally, you also deploy a serverless backend that includes identity, database, storage, and custom APIs that provide the dynamic data for your SPA. AWS provides this kind of serverless backend. You can compose this backend by using the AWS Mobile Hub console. You still need to integrate the AWS SDK for JavaScript into your SPA. In this post, we walk through that integration.

Add the AWS SDK for JavaScript to your project

The SDK is distributed via the npm package manager. To install the SDK into your project, use the following command:

npm install –save aws-sdk

This downloads the SDK and adds an entry into the package.json file so that the SDK is downloaded automatically when it is needed. In addition, any dependencies for the SDK are downloaded and included in your project.

Download the AWS configuration for your project

In the last article, we showed you how to create an AWS Mobile Hub project and turn on the Hosting and Streaming service. This also generates two files in the Amazon S3 bucket that is created:

  • aws-config.js is used by browser sessions to configure the SDK.
  • aws-exports.js is used by SPA applications that are packed (by Webpack, Browserify, or similar tools) to configure the SDK.

You need the aws-exports.js file for the React app. You can download this file from the Amazon S3 bucket using either the AWS Mobile Hub console or the AWS CLI. To download via the CLI, use the following:

aws s3 cp s3://bucket/aws-exports.js ./src/aws-exports.js

From the AWS Mobile Hub console:

  1. Sign in to the AWS Mobile Hub console.
  2. Choose your project.
  3. Choose Hosting and Streaming.
  4. Click Download aws-exports.js file.

You can (and should) do this before every build. I have included the following in my package.json:

{
	"scripts": {
		"prebuild": "aws s3 cp s3://${S3BUCKET}/aws-exports.js ./src/aws-exports.js",
		"build": "react-scripts build",
		"deploy": "aws s3 cp ./build s3://${S3BUCKET}/ --recursive",
		"start": "react-scripts start",
		"test": "react-scripts test –env=jsdom",
		"eject": "react-scripts eject"
	},
	…
}

Set the S3BUCKET environment variable and build the React app as follows:

# For MacOS or Linux
export S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows cmd
# set S3BUCKET=reacttestapp-hosting-mobilehub-1234567890
# For Windows PowerShell
# $env:S3BUCKET="reacttestapp-hosting-mobilehub-1234567890"

# Now run the build
npm run build

Integrate the SDK into your app

In each SPA, there is an entry point. The entry point for all apps created by create-react-app is the src/App.js file. The create-react-app tool uses ES2015 modules.  This means we can use the import keyword to bring in the aws-exports.js file:

/*
 * Import the SDK and Project Configuration
 */
import AWS from 'aws-sdk';
import awsmobile from './aws-exports';

/*
 * Configure the SDK to use anonymous identity 
 */
AWS.config.update({
  region: awsmobile.aws_cognito_region,
  credentials: new AWS.CognitoIdentityCredentials({
    IdentityPoolId: awsmobile.aws_cognito_identity_pool_id
  })
});

In this snippet, we import both the SDK and the configuration of the backend, and then automatically create identity credentials for Amazon Cognito based on the configuration. We can also use this to instantiate an Amazon DynamoDB connection or call an Amazon API Gateway REST endpoint using the SDK.

What’s in the aws-exports.js

The aws-exports.js file is a standard JavaScript file that is maintained by AWS Mobile Hub on your behalf. It changes when you add, remove, or edit features within AWS Mobile Hub. An example from one of my apps is below:

// WARNING: DO NOT EDIT. This file is Auto-Generated by AWS Mobile Hub. It will be overwritten.

// Copyright 2017 Amazon.com, Inc. or its affiliates (Amazon). All Rights Reserved.
// Code generated by AWS Mobile Hub. Amazon gives unlimited permission to
// copy, distribute and modify it.

// AWS Mobile Hub Project Constants
const awsmobile = {
aws_app_analytics : 'enable',
aws_cognito_identity_pool_id : 'us-east-1:XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX',
aws_cognito_region : 'us-east-1',
aws_content_delivery : 'enable',
aws_content_delivery_bucket : 'XXXXXX-hosting-mobilehub-1234567890',
aws_content_delivery_bucket_region : 'us-east-1',
aws_content_delivery_cloudfront : 'enable',
aws_content_delivery_cloudfront_domain : 'XXXXXXXXXXX.cloudfront.net',
aws_mobile_analytics_app_id : 'XXXXXXXXXXXXXXXXXXXXXXX',
aws_project_id : XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX ',
aws_project_name : 'XXXXXX’,
aws_project_region : 'us-east-1',
aws_resource_name_prefix : 'XXXXXX-mobilehub-1234567890’,
}

export default awsmobile;
var AWS = require('aws-sdk');
AWS.config.region = awsmobile.aws_project_region;
AWS.config.update({customUserAgent: 'MobileHub v0.1'});

This project has the following enabled:

  • Analytics (from the Messaging and Analytics feature)
  • Hosting and Streaming

You can see the appropriate IDs are available through constants that are then exported as a module. You should never edit this file directly. Instead, change the features within your AWS Mobile Hub project and then copy the file to your source code control again.

Best Practices

We consider the following best practices for integrating the SDK:

  1. Always use the latest version of the SDK.
  2. Add the src/aws-exports.js file to your .gitignore (or similar) file. Do not check this file into your source code repository.
  3. Copy the aws-exports.js file from your AWS Mobile Hub project during the build phase of your app.

Now that you know how to integrate the SDK into your app, you can start using the AWS SDK for JavaScript to access your AWS services. In future articles, we will explore adding AWS service access to your React app. Until then, please see the AWS SDK for JavaScript Developer Guide for more details.

Automated Device Testing with AWS Device Farm and Jenkins

A strong indicator of quality of an app is its ability to run on multiple devices of different make, model, and manufacturer consistently and predictably. Incremental development models are at the core of every mobile app development team. Often a seemingly benign feature can be disruptive to the overall user experience and functioning of the app if not thoroughly tested. How do you ensure that every code check-in triggers tests for your mobile app against numerous devices and provides detailed analysis of the results?

Continuous integration (CI) systems have been around for a long time and are now at the core of all DevOps workflows. They integrate build, test, and distribution into one workflow. Many systems to implement CI exist, including cloud solutions like AWS CodePipeline and on-premises solutions like Jenkins. Jenkins is an open source CI solution that is easy to install and portable across all major platforms. It has more than 1000 plugins that integrate with build, test, and distribution components.  This makes Jenkins a popular choice among teams looking for a CI tool for a new project.

AWS Device Farm is an app testing service. You can use it to test and interact with your Android, iOS, and web apps on physical phones and tablets that are hosted by AWS. You can use Device Farm for automated testing with a variety of available testing frameworks. You can also use it for manual testing through a remote session.

Today, AWS Device Farm announced the availability of a Jenkins plugin for AWS Device Farm.  The Jenkins plugin enables you to integrate device testing into your CI workflow.

Prepare your AWS account so that Jenkins can access Device Farm resources:

  1. Sign in to the IAM console.
  2. Create or modify an IAM policy so that your Jenkins instance has access to AWS Device Farm.
  3. Create a user for your Jenkins master (with programmatic access) and assign the user to the IAM policy you just created.
  4. Note the access key ID and secret access key. You need them later.

Add the Jenkins plugin to your Jenkins master:

  1. Sign in to your Jenkins web UI.
  2. Click Manage Jenkins > Manage Plugins on the left side of the screen.
  3. Click the Available tab.
  4. Type aws-device-farm in the search box.
  5. Click Install without restart.
  6. After the installation is complete, click Manage Jenkins > Configure System.
  7. Scroll to the AWS Device Farm header.
  8. Paste the access key ID and secret access key into the appropriate boxes.
  9. Click Save.

You can also use the Jenkins CLI to manage plugins.  Now that the Jenkins plugin for AWS Device Farm is available on your Jenkins master, you can use it in a workflow:

  1. Select the project for which you want to set up the plugin.
  2. Add a post-build step: Run Tests on AWS Device Farm.
  3. Configure any options you want for the run. At minimum, select the UI tests that you want to run and the devices you want to run those tests on.
  4. Save the changes for the project.

AWS Device Farm supports major testing frameworks such as Espresso, XCTest UI, Appium, and Calabash.

After a build and test flow is complete, you can see the results of the tests:

Integrating AWS Device Farm into your automated build pipeline enables you to test your mobile applications on more devices, producing a better quality mobile app.  As always, we want to hear from you.  If you have suggestions or issues, let us know on the AWS Forums.

Using Amazon DynamoDB Document API with the AWS Mobile SDK for Android – Part 2

In the first part of this blog, we introduced you to the Amazon DynamoDB Document API. This API is a mechanism for accessing data in DynamoDB that doesn’t require you to map models to the data. Instead, you access the data through standard accessor methods on a standard Document object. In this blog post, we show how to integrate this functionality into a real application. The application for this demonstration is an Android memo app. The mobile backend architecture for the app is shown in the following diagram.

The services used are:

This infrastructure can be easily set up using AWS Mobile Hub.  Either click the Deploy to AWS Mobile Hub button in our GitHub repository or follow these instructions:

  1. Click Create a new Project in the AWS Mobile Hub console.  Provide a name for your project.
  2. Click NoSQL Database.
  3. Click Enable NoSQL.
  4. Click Add a new table.
  5. Click Start with an example schema.
  6. Select Notes as the example schema.
  7. Select Public for the permissions (we won’t add sign-in code to this app).
  8. Click Create Table, and then click Create Table in the dialog box.

Even though the table you created has a userID, the data is stored unauthenticated in this example. If you were to use this app in production, use Amazon Cognito to sign the user in to your app, and then use the userID to store the authenticated data.

In the left navigation pane, click Resources. AWS Mobile Hub created an Amazon Cognito identity pool, an IAM role, and a DynamoDB database for your project. Mobile Hub also linked the three resources according to the permissions you selected when you created the table. For this demo, you need the following information:

  • The Amazon Cognito identity pool ID (for example, us-east-1:f9d582af-51f9-4db3-8e36-7bdf25f4ee07)
  • The name of the Notes table (for example, androidmemoapp-mobilehub-1932532734-Notes)

These are stored in the application code and used when connecting to the database.

Now that you have a mobile app backend, it’s time to look at the frontend. We have a memo app that you can download from GitHub. First, add the required libraries to the dependencies section of the application build.gradle file:

compile 'com.amazonaws:aws-android-sdk-core:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb:2.4.4'
compile 'com.amazonaws:aws-android-sdk-ddb-document:2.4.4'

Add the INTERNET, ACCESS_NETWORK_STATE, and ACCESS_WIFI_STATE permissions to AndroidManifest.xml:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

Set up the connection to the Amazon DynamoDB table by creating an Amazon Cognito credentials provider (for appropriate access permissions), and then creating a DynamoDbClient object. Finally, create a table reference:

// Create a new credentials provider
credentialsProvider = new CognitoCachingCredentialsProvider(
        context, COGNITO_POOL_ID, COGNITO_REGION);

// Create a connection to DynamoDB
dbClient = new AmazonDynamoDBClient(credentialsProvider);

// Create a table reference
dbTable = Table.loadTable(dbClient, DYNAMODB_TABLE);

You can now perform CRUD (Create, Read, Update, Delete) operations on the table:

/**
 * create a new memo in the database
 * @param memo the memo to create
 */
public void create(Document memo) {
    if (!memo.containsKey("userId")) {
        memo.put("userId", credentialsProvider.getCachedIdentityId());
    }
    if (!memo.containsKey("noteId")) {
        memo.put("noteId", UUID.randomUUID().toString());
    }
    if (!memo.containsKey("creationDate")) {
        memo.put("creationDate", System.currentTimeMillis());
    }
    dbTable.putItem(memo);
}

/**
 * Update an existing memo in the database
 * @param memo the memo to save
 */
public void update(Document memo) {
    Document document = dbTable.updateItem(memo, new UpdateItemOperationConfig().withReturnValues(ReturnValue.ALL_NEW));
}

/**
 * Delete an existing memo in the database
 * @param memo the memo to delete
 */
public void delete(Document memo) {
    dbTable.deleteItem(
        memo.get("userId").asPrimitive(),   // The Partition Key
        memo.get("noteId").asPrimitive());  // The Hash Key
}

/**
 * Retrieve a memo by noteId from the database
 * @param noteId the ID of the note
 * @return the related document
 */
public Document getMemoById(String noteId) {
    return dbTable.getItem(new Primitive(credentialsProvider.getCachedIdentityId()), new Primitive(noteId));
}

/**
 * Retrieve all the memos from the database
 * @return the list of memos
 */
public List<Document> getAllMemos() {
    return dbTable.query(new Primitive(credentialsProvider.getCachedIdentityId())).getAllResults();
}

There are two mechanisms for searching the dataset: scan and query. The query() method uses indexed fields within the DynamoDB table to rapidly retrieve the appropriate information. The scan() method is more flexible. It allows you to search on every field, but it can run into performance issues when searching large amounts of data. This results in a worse experience for your users because data retrieval will be slower. For the best experience, index fields that you intend to search often and use the query() method.

The Notes schema in DynamoDB usually segments data on a per-user basis. The app works with both authenticated and unauthenticated users by using the .getCachedIdentityId() method. This method stores the current user identity with every new note that is created.

Android does not allow you to perform network requests on the main UI thread. You must wrap each operation in an AsyncTask. For example:

/**
 * Async Task to create a new memo into the DynamoDB table
 */
private class CreateItemAsyncTask extends AsyncTask<Document, Void, Void> {
    @Override
    protected Void doInBackground(Document... documents) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(EditActivity.this);
        databaseAccess.create(documents[0]);
        return null;
    }
}

You can initiate a save operation by instantiating the appropriate AsyncTask and then calling .execute():

/**
 * Event Handler called when the Save button is clicked
 * @param view the initiating view
 */
public void onSaveClicked(View view) {
    if (memo == null) {
        Document newMemo = new Document();
        newMemo.put("content", etText.getText().toString());
        CreateItemAsyncTask task = new CreateItemAsyncTask();
        task.execute(newMemo);
    } else {
        memo.put("content", etText.getText().toString());
        UpdateItemAsyncTask task = new UpdateItemAsyncTask();
        task.execute(memo);
    }
    // Finish this activity and return to the prior activity
    this.finish();
}

Similarly, you can retrieve a list of memos on an AsyncTask and pass the memos back to a method in the MainActivity to populate the UI:

/**
 * Async Task for handling the network retrieval of all the memos in DynamoDB
 */
private class GetAllItemsAsyncTask extends AsyncTask<Void, Void, List<Document>> {
    @Override
    protected List<Document> doInBackground(Void... params) {
        DatabaseAccess databaseAccess = DatabaseAccess.getInstance(MainActivity.this);
        return databaseAccess.getAllMemos();
    }

    @Override
    protected void onPostExecute(List<Document> documents) {
        if (documents != null) {
            populateMemoList(documents);
        }
    }
}

You can find this sample in our GitHub repository. To run the sample:

  1. Open the project in Android Studio.
  2. Open the DatabaseAccess.java file.
  3. Replace the temporary string for COGNITO_POOL_ID with your Amazon Cognito Identity Pool ID.
  4. Replace the temporary string for DYNAMODB_TABLE with your Amazon DynamoDB table name.
  5. If necessary, replace the COGNITO_REGION with the region for your Amazon Cognito identity pool ID.
  6. Run the app on a real device or the Android emulator.

If you are successful, the app looks like the following:

The Document API is currently in beta. We would like to hear about the use cases you want us to support. You can leave your feedback and issues on our forums and GitHub.

Using Amazon DynamoDB Document API with AWS Mobile SDK for Android – Part 1

The AWS Mobile SDK for Android helps developers write mobile apps by providing simplified APIs for using AWS services, such as Amazon Cognito and Amazon DynamoDB. In the past, to access data, you needed to use the DynamoDB Object Mapper (or use the service APIs). You then had to define a model within your mobile code that mirrors the model defined in the table for DynamoDB. This meant more code to write and test. With v2.4.4 of the SDK, we are introducing a new feature, which we call the Document API. With the Document API, you no longer need to use the DynamoDB Object Mapper; instead, you access individual fields within data objects directly.

What is the difference between the Object Mapper and the Document API?

The Document API provides a simplified interface to access the NoSQL data that is returned by DynamoDB. You no longer need to update schema or map the table properties to class members. The Document API provides new data types to assist in the serialization and deserialization process. The DynamoDB Object Mapper maps client-side model classes to DynamoDB tables.

Both APIs provide methods to perform create / update / delete (CRUD) operations and execute queries against the DynamoDB tables. The difference between the two APIs is in how the data is represented as you manipulate it within your mobile app.  This enables you to select the API that you feel is better for your situation. You can even mix and match. For example, you can use the Object Mapper for data in one table, and use the Document API for data in another table.

Working with the Document Object

When working with the Document API, you primarily work with a Document. A Document is the container for the data returned from or pushed to the Amazon DynamoDB database.

You can convert between JSON and Document objects. However, you will lose fidelity when converting from a Document object to JSON. This is because not all data types that can be stored in DynamoDB can be represented in JSON. Use Document.fromJson() and Document.toJson() to perform the conversion. For example:

Document myDocumentObject = Document.fromJson(myJsonString);
String myJsonString = Document.toJson(myDocumentObject);

The Document object accepts standard JSON types, like string, number, or Boolean:

Document doc = new Document();
doc.put(“stringField”, “value”);
doc.put(“numberField”, 2.0F);
doc.put(“booleanField”, true);

The Document object also accepts JSON arrays (represented as a set of items) and JSON maps (represented as another Document):

// An unordered list
Set<String> coll = new HashSet<String>();
coll.add(“string1”);
coll.add(“string2”);
doc.put(“arrayField”, coll);

// A key-value map
Document name = new Document();
name.put(“first”, “Adrian”);
name.put(“last”, “Hall”);
doc.put(“name”, name);

The Document object also accepts Amazon DynamoDB types, such as binary data, null, and ordered lists:

//null field
doc.put(“nullField”, DynamoDbNull.NULL);

// Binary Data
ByteBuffer buffer = new ByteBuffer();

// Populate the buffer with binary data
doc.put(“binaryField”, new Primitive(buffer));

// An Ordered List
DynamoDbList ddl = new DynamoDbList();
ddl.add(“string1”);
ddl.add(“string2”);
doc.put(“orderedList”, ddl);

You can access data within a Document object using the document path. For example:

String stringField = doc.get(“stringField”);
String firstName = doc.get(“name.first”);

If you do not know which data type is being returned, use the DynamoDbEntry type, and then compare it against the known types:

DynamoDBEntry entry = doc.get(“orderedList”);
If (entry instanceof DynamoDBList) {
    dynamoDBList list = entry.asDynamoDBList();
    for (Iterator I = list.iterator(); i.hasNext(); ) {
        DynamoDBEntry listEntry = (DynamoDBEntry)i.next();
    }
}

You can also use entry.asString(), entry.asNumber(), etc. to convert to more primitive types.

Handling Data with the Document API

Document objects are used as the unit of transfer between your mobile app and Amazon DynamoDB. Each of the CRUD operations within the Document API either accepts or returns a Document object. First, create an Amazon DynamoDB client, then get a reference to the DynamoDB table:

DynamoDBClient client = new DynamoDBClient(awsCredentialProvider, config);
Table myTable = Table.loadTable(client, “MyTable”);

Once you have a reference to the table, you can use putItem(), getItem(), updateItem() or deleteItem() to perform CRUD (create, read, update, delete) operations. For example, if you know the key of the item that you want to retrieve, you can use this key to retrieve the document, obtain the text content, and assign it to an Android control:

Document retrievedDoc = myTable.getItem(new Primitive(“key”));
myTextView.setText(retrievedDoc.get(“stringField”).asString());

If the user has changed the text, you can update the document as follows:

retrievedDoc.set(“stringField”, myTextView.getText());
Document updatedDoc = myTable.updateItem(retrievedDoc);

You can also query for data using the Document API. For example, to find all Document objects where the Age field is greater than 5:

final Expression expression = new Expression();
expression.setExpressionStatement("Age > :age");
expression.withExpressionAttibuteValues(":age", new Primitive(5));
Search searchResult = table.scan(expression);
List<Document> documents = searchResult.getAllResults();

The table.scan() method performs a query across all fields in the table, which is probably not the most optimal method for querying the table. If you have a partition key called userId (which contains the user’s ID), then you can run queries across a single partition using the table.query() method:

final Expression expression = new Expression();
expression.setExpressionStatement("Tag = :tag");
expression.withExpressionAttibuteValues(":tag", new Primitive(“sports”));

Search searchResult = table.query(new Primitive(“myUser”), expression);
List<Document> documents = searchResult.getAllResults();

This method will have better performance because DynamoDB is scanning fewer records.

Document API limitations

The DynamoDB Document API does not currently support:

  1. Data types such as S3Link, Date, Calendar, etc.
  2. Batch operations.
  3. Conditional expressions.

The Document API is currently in beta and we would like to hear about the use cases you would like us to support. You can leave your feedback and issues on our forums and GitHub.

In the second part of this blog, we will describe how to integrate the Document API into a real Android app and provide a sample app that shows the Document API in action.

Deep Linking – Track and Engage Mobile App Users

You are about to enter the incredibly engaging and often confusing world of mobile deep linking. You’ll learn what deep linking is—the types of links, what deep linking can do, and why you should care—and walk through implementation details with examples.

What is Deep Linking?

Think of a deep link as a URL that takes you to a specific page or product within a website. Deep links are designed to send the mobile user to your app or content within your app, if installed. If not installed, links can launch a website or redirect a user to an app store to install the app.

There are three levels of deep linking: basic, deferred, and contextual. Each type is explained below.

Basic Deep Link

The basic form of deep linking is specifying a custom name for your app as a target for other mobile apps to launch your app and display specific content. This allows you to keep the user within the mobile app experience. If the user already has your app installed, this is cool. If your app isn’t installed, what happens?

The basic deep link works well when the app is installed but fails when it is not installed because the operating system does not know where to redirect.

Deferred Deep Link

A deferred deep link improves on the basic level. It informs the OS to redirect the user to a website or app store to download the app if the app is not installed. The website can display the content on a mobile browser if needed.  Or, if the user downloads and launches the app, the deep linked content is remembered. The user is presented with the intended content, just as if the user had the app installed in the first place.

Here’s an example flow that shows the value of deferred deep linking. The user is presented with three options. After selecting the circle object, the user is directed one of two ways: If APP 2, which is selling the object, is not installed on the user’s mobile device, the user is redirected to the app store. The user downloads and launches APP 2 and is then presented with, and can purchase, the discounted circle object that was originally selected in APP 1 as a promise. The discounted circle object content was deferred for the user until the user installed and launched APP 2. The user can now add the circle to the shopping cart with the applied discount, all within the native mobile app experience.

 

Deferred deep linking has the basic flow of launching an app to specific content but takes it a step further by enhancing the user experience. This helps acquire more users and improves the retention of existing users. It requires a little more effort in the implementation but handles most use cases for mobile user interaction and engagement.

Contextual Deep Link

The final stage is contextual deep linking. Contextual deep linking takes the basic and deferred links to a new level but looks exactly the same to the end user. With contextual, you are just adding valuable metrics (e.g., referrers, coupons, user attributes, and so on) to track every user interaction, from the user clicking the link to making a purchase in the mobile app. Let’s look at this interaction:

 

Contextual deep linking follows the same basic and deferred pattern but enables you to track the activity of your users throughout their mobile journey. In this case, contextual deep linking can carry information such as referrals, the pages within your app they were sent to, the promotional codes they use, the pages they visit within your app, etc. Access to this data can increase user conversion and app retention, all while giving your users a consistent, smooth, single-platform mobile experience.

What Does Deep Linking Do?

When a mobile app is configured for deep linking, it allows users to launch your mobile app directly (if installed on their device) to specific content within the app.  If the app is not installed, the user can be redirected to specific content on a website or directed to download the app in the app store. If the app is installed and launched, the original content is displayed in the mobile app. A deep link can also be set up to route specific content to a mobile browser where it makes sense.

How Does Deep Linking Work?

The app developer creates a unique name for his or her app and configures the app to handle redirection of an incoming link to a page, product, or announcement within the app. Deep links indicate to the OS how to handle these incoming links so that the result is seamless (no visual redirects) and users are taken directly to the intended endpoint. Each platform has a different implementation but the end user flow is the same.

What Does a Deep Link Look Like?

Each mobile platform and OS has its own implementation but they have similar patterns to a URL as explained earlier. The latest deep link integration for both iOS and Android looks like traditional URLs (for example, http://myapp.com/path/to/content). However, previous versions of iOS and Android used a URI like this: myapp.com://path/to/content.

In the implementation, apply deferred deep linking as a URL and use a URI as a fallback. This enables you to handle third-party app flows that only support the URI scheme and users running a previous version of the OS.

Let’s Get Started

First, look at the following chart. It shows platform-specific support for deep linking. It’s important to understand the terms and implementation details for each platform and OS version.

Platform Specific Deep Linking Integration Instructions

For all iOS applications, use the latest Apple universal links for deep links introduced with iOS 9.2. For versions earlier than iOS 9.2, use Custom URI Schemes.

To enable universal links for iOS, Apple requires that your has Associated Domains enabled in the Apple Developer Portal and in your Xcode project. In addition, you’ll need to upload and host a configuration file (apple-app-site-association) at the root of your web server (this could even be a static web hosting enabled S3 bucket).

Get Started by following these steps to integrate universal links into your iOS app:

  1. Enable Associated Domains for your App ID in the Apple Developer Portal.
  2. In your Xcode project, enable Associated Domains under App Target > Capabilities.
  3. In the Domains field, add your website domain appended to applinks: as shown here: applinks:domain.com.
  4. Add a restorationHandler function to your iOS project AppDelegate to handle the incoming links.
  5. Add the Apple apple-app-site-association JSON file (without the .json extension) to the ROOT of your secure web server. Use the domain you provided in step #3 (your website must be served using HTTPS).
  6. Launch the app so that it registers the domain.

Done.

You can test the universal link functionality by sending a link with the URL specified in associated domains to your email or SMS. Selecting the link opens the app. The app’s restorationHandler in the AppDelegate manages the link URL and any attributes.

Universal link caveats:

  • iOS remembers the user’s first choice when opening universal links. If the user taps the top-right breadcrumb to open the link in Safari, all further taps take the user to Safari, and not open within the app. The user can switch back to opening the app (instead of the browser) by choosing Open in the app banner within Safari.
  • Universal links only work for iOS 9 and later. Universal links in early versions of iOS 9 only work on the device; they do not work on the simulator.
  • For users who are running versions of iOS earlier than 9.0, tapping a universal link to your website opens the link in Safari.

For all Android apps as of API 6.0, use Android App Links. For API version 5 and earlier, use Android Chrome Intents.

The easiest way to implement Android App Links is to use App Links Assistant, introduced in Android Studio 2.3. The assistant is a step-by-step wizard for setting up Android App Links. The wizard walks you through the following.

Launch your Android Studio 2.3 project and select Tools > App Links Assistant.

A.   URL Mapping

  1. Select Open URL Mapping Editor button
  2. Select ‘+’ to add a new URL Mapping
  3. Provide a URL
  4. Provide a path
  5. Select OK

B.     Add code to your app’s activities to handle incoming links.

  1. Select the Select Activity button
  2. Highlight the activity
  3. Select Insert Code button

C.     Associate your mobile app and your web site with Digital Asset Links.

  1. Select Open Digital Asset Links File Generator button
  2. Provide your domain
  3. Select Signing config radio button
  4. Select Generate Digital Asset Links file
  5. Upload the assetlinks.json file to the location as shown
  6. Select Link and Verify button

You are done with Android deep linking integration instructions. Congratulations!

Contextual Deep Linking Analytics

Using the contextual deep linking approach, you can track your campaigns and funnels by sending custom events to Amazon Pinpoint. Here’s a high-level overview of how you can track your campaigns by storing each interaction as a custom event using Pinpoint.

  1. Launch the AWS Mobile Hub console.
  2. Create a project.
  3. Choose User Engagement.
  4. Download the iOS Swift project sample app.
  5. Follow the six previous steps to enable universal links for iOS.
  6. In your Xcode project, navigate to the restorationHandler function within your AppDelegate. Add the following snippet of code to send a custom event to Amazon Pinpoint when a universal link is selected. The sample code with hard-coded key/values. You capture these values from the incoming referring linked attributes.

Here’s what the custom event looks like in the Amazon Pinpoint console:

Deep Linking Terminology

Apple Universal Links – The latest version of deep linking for iOS, as of iOS 9.2.

Android App Links – The latest version of deep linking for Android as of version 6.

URI Scheme – The original deep linking format on iOS, before version iOS 9.2. A URI Scheme for deep linking looks something like appname://page/1234, where appname is your unique app name and page/1234 is the page content within the app that is installed on the user’s iOS device.

Android Intent with Chrome – A feature in Android that you use to launch an app directly from a webpage via an Android intent. This feature works in the Chrome for Android browser, version 18 and earlier.

Deferred Deep Links – A deep link that points to content inside a mobile app that is not yet installed. The link brings the user to the download page in the app store. After downloading the app, the user launches the app and is taken directly to the content within the app.

Conclusion

In nearly all categories, mobile app developers can benefit by implementing deep links into their own apps. The implementation process can be a bit involved but once you apply the platform-specific requirements, the benefits far outweigh the additional effort.

Happy linking everyone!

Web and Hybrid Mobile App Solution from AWS Mobile Hub and Ionic

AWS Mobile Hub and Ionic, an open source framework for building mobile apps, have teamed up to create an official Ionic starter project that demonstrates an end-to-end solution for hosting and building mobile web and hybrid applications on AWS.

In this blog post, we explain what the project is, describe key areas, highlight additional use cases, and then send you on your way to get started.

What is the official Ionic AWS starter project?

The Ionic team used the new Mobile Hub project export/import feature to build an official Ionic AWS starter project (Ionic blog | GitHub). The project demonstrates how quick and easy it is to deploy an end-to-end Ionic application on AWS using Mobile Hub.

The Ionic starter project is a sample mobile and web “todo task list” app based on a pre-configured AWS Mobile Hub project. After you import this exported Mobile Hub project from Ionic, Mobile Hub provisions the backend services. The Ionic project shows how to securely authenticate users with Amazon Cognito User Pools and receive AWS credentials. At that point, the user can read and write application data to Amazon DynamoDB and store user profile images to Amazon S3.

What is Ionic?

Ionic is an open source framework for building cross-platform hybrid mobile applications using web technologies like HTML, CSS, and JavaScript. Ionic is built on top of AngularJS and Apache Cordova. Ionic apps can be distributed through native app stores by using Apache Cordova API to call JavaScript functions that map to native code or plugins.

What is deployed on AWS?

Let’s look at the backend resources. After importing the exported project from Ionic, Mobile Hub creates a new project, and then enables and provisions the User Sign-in, NoSQL Database, User Data Storage, and App Content Delivery features. The Mobile Hub feature cards are curated common mobile use cases consisting of one or more AWS services. To learn more about these Mobile Hub features, click here.

To get started, download the mobile-hub-project.zip from GitHub and navigate to the Mobile Hub console. Click Import your project and drop the .zip file into the dialog box. Select Import Project. Mobile Hub creates the project and resources.

The purple cards indicate the enabled features, which were auto-generated by the Ionic imported project template.

Let’s explore the enabled backend features of your AWS Ionic Starter Project and see what they do.

User Sign-in: This feature creates an Amazon Cognito User Pool for identity management. The user pool allows your users to authenticate (sign-up and sign-in). After a user authenticates, they are provided a unique identifier by Amazon Cognito. That identity is used to generated temporary, limited-privilege AWS credentials to directly access your resources.. That identity is used when creating, editing, and deleting tasks within the app. Only the task that the authenticated user creates is available to the user. And… no more secret keys!

To view the configuration and a list of your users in the Amazon Cognito console, go to your Mobile Hub project, select resources, and then choose the direct link to your Amazon Cognito User Pools.

NoSQL Database: This creates a single Amazon DynamoDB table called “ionic-mobile-hub-tasks” for storing each task. Here’s what the data looks like (in the Amazon DynamoDB console) after creating a few tasks in the Ionic app. The userId is the Identity given to that user by Amazon Cognito.

To view the table data within the DynamoDB console, go to your Mobile Hub project, select resources, and then choose the direct link to your table under Amazon DynamoDB Tables.

User Data Storage: This created a single Amazon S3 bucket that is used to store files such as photos or other user content. When running the Ionic app on a device, users can click their account settings and change their profile picture, which stores the image in the S3 bucket.

App Content Delivery: This is the core of the Ionic web application. This feature created a single S3 bucket. In the S3 bucket, you’ll see some sample images along with the AWS SDK for JavaScript, aws-config.js, and a default index.html file. In addition, the S3 bucket is configured as a website to demonstrate the ability to host web content directly from your S3 bucket without having a web server. Because an Ionic application can be run either on a device as a native app or as a web app, the app can be hosted on an S3 static website.

Here’s a list of the bucket contents after enabling the App Content Delivery feature within Mobile Hub but before copying the web assets from your Ionic starter project.

In the Ionic starter project instructions, you copy the aws-config.js from here to your project to run the app locally. Instead of running your app locally using “$ionic serve” you just copy the web assets in your myApp/www/ to the root of your S3 bucket. To do this inside your Ionic project, run the following commands, substituting WEBSITE_BUCKET with the S3 content delivery bucket name that was created by the Mobile Hub project import.

npm run build
aws s3 cp --recursive ./www s3://WEBSITE_BUCKET

To learn more about setting up a static website on Amazon S3, see the Amazon S3 Developer Guide.

What have we built today?

The Ionic starter project provides a full end-to-end experience. Once configured, the app is quite diverse and is truly cross-platform. The same code base can be run locally as a web app in a browser, deployed to an iOS or Android device as a hybrid mobile app, or served from an S3 bucket for desktop and mobile browser users. The app showcases the ability to sign in from any device or browser and then sign in on another device: the user’s task list follows the sign-in because the data that is stored in Amazon DynamoDB is associated with that user.

Here’s a look at the interaction with the Ionic todo app from different platforms:

Running the web app locally and interacting in a desktop browser

 

Interacting with the web app served from Amazon S3, using a desktop browser

Ionic starter web app running from an installed app on an iOS device

 

The mobile web app being served from Amazon S3 on a mobile browser

 

Get Started

You’ll find the Ionic + AWS Mobile Hub Starter Project on GitHub. The README walks you through using the starter, installing the necessary CLIs, creating the project, running the app, and deploying the project’s web assets to the S3 bucket.

Additional Resources

AWS What’s New
Ionic Blog
Ionic on AWS