Tag: React Native


Announcing: React Native Starter Project with One-Click AWS Deployment and Serverless Infrastructure

React Native as a mobile development platform continues to grow in popularity. AWS has invested more in this area over the past year, and has been participating in React Native community events. Many developers want to enrich applications that they built using React Native with features like database access and content storage (images, videos, etc.), while protecting these resources with strong security mechanisms. Adding functionality such as user registration, sign-in, and MFA flows can be challenging to do in a cost effective and scalable manner.

Today, we’re announcing a new React Native starter project which has been open sourced on GitHub to help customers quickly add these features using AWS services. The project contains a starter application that can be run with a single click, using the Deploy from GitHub button capabilities of AWS Mobile Hub. After deployment finishes, the starter can be run locally using npm or yarn on either iOS or Android. The project demonstrates user sign-up and sign-in flows along with MFA as a “Pet Tracker” application, allowing you to upload pictures of your pets along with some data (name, age, breed, and gender). The pictures are stored in an S3 bucket. The bucket can only be accessed by the user. Similarly, the records corresponding to these pictures are stored in an Amazon DynamoDB table on a per-user basis as well. This is protected by a serverless infrastructure that uses Amazon API Gateway and AWS Lambda.

In addition to the starter application, which you can modify to fit your needs, the project contains several Higher Order Components (HOCs) that you can use in your application. For instance, there is a WithAuth HOC that you can use to add just the sign-up, sign-in, and MFA portions of the project to your application. Similarly, there are HOCs for secure API and storage access as well.

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

  • Amazon Cognito User Pools and Federated Identities
  • Amazon API Gateway, AWS Lambda, and Amazon DynamoDB
  • Amazon S3, including bucket policies and folder structures for private and public content
  • IAM roles and policy for the Lambda execution role
  • IAM roles and policy for the user roles that access API routes and S3 buckets after authentication

Prerequisites

To get the starter running quickly you need the following:

  • AWS account
  • NodeJS with NPM
  • React Native CLI
    • npm install -g react-native-cli
  • (optional) AWS CLI

You can find the starter project demonstrating this functionality on GitHub. The repository describes the steps to get everything running and information about how to incorporate HOCs into your own application. In this blog post, we dive into some extra details.

Installation

Clone the GitHub repository.

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-native-starter/client folder of the cloned repo.

Use the following commands to run the application:

cd ../aws-mobile-react-native-starter/client
npm install
npm run ios #npm run android

Walkthrough of the application

After the application is running, you can see the SIGN IN screen. If this is your first time running the application, choose the SIGN UP tab in the lower right and complete the process with a username, password, email address, and valid phone number.

You will receive a confirmation code for signing up through SMS; enter the code in the prompt.

Navigate back to the main sign-up screen with your new user name and password. You’ll get another SMS verification code, this time as part of the MFA process. After signing in, you will see a blank screen. Choose plus (+) in the lower right and either take a picture of your pet or upload an existing image from your camera roll. Fill out the details such as name, date of birth, breed, and gender, and then choose Add Pet.

This stores the image in an S3 bucket and stores the record in Amazon DynamoDB, using Amazon API Gateway and AWS Lambda. The main screen shows this record and you can click it any time. The records are protected on a per-user basis, which is described later in this post.

Details and customizations

Storing data from your Camera Roll

In the Storage section of the starter repository, there is a walkthrough that describes how to adding capabilities to upload images to an S3 bucket. The image comes from an existing AWS URL in this HOC walkthrough. The starter application, however, contains code for uploading to Amazon S3 using CameraRoll, which requires a native bridge. The logic for this process is contained in the AddPet component, which you can view here and here.

The getPhotos() function pulls the images off of the Camera Roll:

  getPhotos = () => {
    CameraRoll
      .getPhotos({
        first: 20,
      })
      .then(res => {
        this.setState({ images: res.edges })
        this.props.navigation.navigate('UploadPhoto', 
		  { 
		    data: this.state, 
			updateSelectedImage: this.updateSelectedImage 
		})
      })
      .catch(err => console.log('error getting photos...:', err))
  }

You can use this utility function in your React components to open the Camera Roll and return an image. Set the function as a State value called images, which is a list of images passed to a function called updateSelectedImage(). This can be used with the TouchableWithoutFeedback component to show a camera dialog:

<TouchableWithoutFeedback onPress={this.getPhotos}>
{
    selectedImageIndex === null ? (
    <View style={styles.addImageContainer}>
        <Icon size={34} name='camera-roll' color={colors.grayIcon} />
        <Text style={styles.addImageTitle}>Upload Photo</Text>
    </View>
    ) : (
        <Image
        style={styles.addImageContainer}
        source={{ uri: selectedImage.node.image.uri }}
        />
    )
}
</TouchableWithoutFeedback>

The readImage() function is provided to have a consistent object across Android and iOS. The Camera Roll on these platforms is returned differently: on Android, the MIME type is present but it is not present on iOS. This function sets the MIME type on iOS using the result of a lookup on the file extension (for instance PNG will result in image/png).

Modifying the import process

An earlier starter project for React includes details on customizations for the Cloud Logic functionality for Amazon API Gateway and AWS Lambda. You may also want to make changes to the Amazon Cognito configuration or the Amazon DynamoDB settings. If you look in the ./backend/import_mobilehub directory of the repo, there is a file called reactnative-starter.zip, which contains the YAML file that AWS Mobile Hub uses on One-Click import. Open this and look at the following section:

  
database: !com.amazonaws.mobilehub.v0.Database
    components:
      database-nosql: !com.amazonaws.mobilehub.v0.NoSQLDatabase
        tables:
          - !com.amazonaws.mobilehub.v0.NoSQLTable
            attributes:
              petId: S
              userId: S
            hashKeyName: userId
            hashKeyType: S
            rangeKeyName: petId
            rangeKeyType: S
            tableName: ___DYNAMIC_PREFIX___-pets
            tablePrivacy: protected

This section of code is what configures an Amazon DynamoDB table, which the AWS Lambda function uses as part of its environment variables. As outlined in our previous blog post, AWS Mobile Hub creates some default environment variables when importing a project, which you can use in your code. From your cloned repo, open ./backend/lambdas/crud/app.js and notice the following code:

const PETS_TABLE_NAME = `${process.env.MOBILE_HUB_DYNAMIC_PREFIX}-pets`;
AWS.config.update({ region: process.env.REGION });

These variables were automatically added to the AWS Lambda function configuration on import. You can view this in the console by clicking the Cloud Logic section of your Mobile Hub project, expanding the View resource details section, and clicking the Lambda function.

Additionally, in the YAML file are features for sign-in and user-files like in the following snippet:

sign-in: !com.amazonaws.mobilehub.v0.SignIn
    attributes:
      enabled: true
      optional-sign-in: true
    components:
      sign-in-user-pools: !com.amazonaws.mobilehub.v0.UserPoolsIdentityProvider
        attributes:
          alias-attributes:
            - preferred_username
            - phone_number
          mfa-configuration: ON
          name: userpool
          password-policy: !com.amazonaws.mobilehub.ConvertibleMap
            min-length: "8"
            require-lower-case: true
            require-numbers: true
            require-symbols: true
            require-upper-case: true
  user-files: !com.amazonaws.mobilehub.v0.UserFiles
    attributes:
      enabled: true

These features control settings, like the password policy or requiring MFA for the sign-up and sign-in process. You can use them with the starter application and when using this import with the WithAuth HOC. You can also control the creation of the S3 bucket for user content above in the user-files setting.

Fine-grained security controls

The starter application as part of the AWS Mobile Hub import process configures an IAM policy that allows users to read and write only their data. This means that the content they put in S3 buckets is private only to that logged in user and the records in the DynamoDB table (written by Amazon API Gateway and AWS Lambda) can only be read and written by that user.

To view this, in the Mobile Hub console for your project, click Resources on the left of the console and find the section labeled AWS Identity and Access Management Roles. Click the link that starts with reactnativestarter_auth_MOBILEHUB-XXXXXX. This opens the role in the IAM console that the user gets when he or she signs in. There are two policies to look at:

  1. Per-user security on S3: This is controlled by the policy that starts with reactnativestarter_userfiles. If you view the policy JSON, notice that it has Resource settings that look similar to the following:
     "Resource": [
         "arn:aws:s3:::BUCKET/public/*",
         "arn:aws:s3:::BUCKET/protected/${cognito-identity.amazonaws.com:sub}/*",
         "arn:aws:s3:::BUCKET/private/${cognito-identity.amazonaws.com:sub}/*"
     ]
    

These policy variables validate the Amazon Cognito Identity per-user that was assigned upon account registration and initial sign-in. This means that only a specific user can access his or her protected or private folders, while the public folder anyone can access.

  1. Per-user security in API Gateway, Lambda, and DynamoDB: This is controlled by the policy that starts with reactnativestarter_ as well as AWS Lambda. First, note the following condition in the policy JSON:
    "Condition": {
         "ForAllValues:StringEquals": {
             "dynamodb:LeadingKeys": [
                 "${cognito-identity.amazonaws.com:sub}"
             ]
         }
     }
    

This condition controls writes to Amazon DynamoDB in this starter project so that only users can write to their data but everyone can read the database records. You can also modify this policy to apply to both writes and reads as another example.

Finally, since the users access DynamoDB through Amazon API Gateway and AWS Lambda, we extract the identity in the Lambda function. If you view ./backend/lambdas/crud/app.js, you will notice that the condition for reading and writing to Amazon DynamoDB leverages the Amazon Cognito Identity ID:

dynamoDb.query({
    TableName: PETS_TABLE_NAME,
    KeyConditions: {
      userId: {
        ComparisonOperator: 'EQ',
        AttributeValueList: [req.apiGateway.event.requestContext.identity.cognitoIdentityId || UNAUTH],
      },
    },

The value req.apiGateway.event.requestContext.identity.cognitoIdentityId is provided by the AWS Serverless Express middleware library that allows this Lambda function to run as an Express server:

const awsServerlessExpressMiddleware = require('aws-serverless-express/middleware');

Wrapping up

As React Native continues to grow, we’re looking forward to bringing more to the ecosystem with the capabilities of this starter project. We hope the combination of React Native and AWS Mobile Hub accelerates your next project. Please give us feedback in the GitHub issues section of the repository.

Targeted push notifications and campaign management using Amazon Pinpoint and React Native

This post was authored by Michael Labieniec, AWS Solutions Architect

Amazon Pinpoint makes it easy to run targeted campaigns to drive user engagement with mobile apps. Using Amazon Pinpoint you can understand user behavior, determine which users to engage with your campaigns, determine which messages to send, schedule the best time to deliver the messages, and then track the results of your campaign. Building cross-platform mobile apps and engaging with users across these platforms can be challenging; it requires you to maintain multiple code bases to take advantage of native features using the AWS Mobile SDK.

React Native enables you to create cross-platform mobile apps while utilizing native features. By building custom native modules, you can interact with the native AWS Mobile SDK generated by AWS Mobile Hub. This means that you maintain a single code base, while customizing the look and feel per platform within React Native. In this example, we will show how to build a native module for the Android platform. The same concepts can be applied to iOS by building a custom module and using the Mobile Hub-generated package.

In this tutorial, you generate a Mobile Hub app that uses an unauthenticated Amazon Cognito identity pool and interacts with API Gateway and AWS Lambda. This app allows you to purchase round trip tickets to your favorite planet. The app generates monetization events using the native AWS Mobile SDK. It then creates custom user attributes for Amazon Pinpoint so you can engage with users based on their planet interest, traveled to destination, and weather preference. To add user authentication along with features such as registration and MFA, consider using the Amazon Cognito User Pools functionality, which you can enable in Mobile Hub.

Requirements

Clone the completed sample app from Github and use the files within this repository as reference when creating your app.

git clone https://github.com/awslabs/aws-pinpoint-sample

Once you have node.js and npm, you can get started by running the following commands from the terminal:

npm install -g react-native-cli
react-native init PinpointSample
cd PinpointSample

NOTE: If you name your project something other than “PinpointSample”, you will need to find/replace the  references in the sample code with your new project name.

Creating the API for your cross-platform app

Go to the AWS Mobile Hub console and click Create new mobile project. In this example for this tutorial, the app name is PinpointSample. Enter the name then click “Create Project”. In the list of features, choose Cloud Logic and then choose Create new API. Give the API a name PinpointSampleApi and a description, leave the defaults, and choose Create API. This API will simply return back whatever you send to it in the request body. You will use this API later in this tutorial to simulate requesting weather information for specific planets.

CREATE_IN_PROGRESS appears while the APIs are being created. When the status is CREATE_COMPLETE, choose “Configure more features”.

image005

Getting a GCM Sender ID and API Key

To send push notifications to Android devices, you need Google Cloud Messaging keys. To create a new Sender ID and API Key, go to https://firebase.google.com.

  • Choose an existing project or create a new project.
  • Click Add (another) app and select Android

Type your package name from the generated React Native app. In this example, it’s com.pinpointsample. Then click Add App. Click Continue and then Finish. Note, you don’t need the google.json file.

Click the menu icon to the right of your new app’s name and then choose Manage Settings. Choose the CLOUD MESSAGING tab. Copy the Sender ID and Legacy Server Key (this is the API Key).

Enabling User Engagement

In the AWS Mobile Hub console, choose User Engagement and then choose Enable engagement and select Android

  • In Sender ID, add the Sender ID from the previous procedure.
  • In API Key, add the Server Key from the previous procedure.

Click Save changes then choose Integrate with your app. Next choose the Android tab, and then choose Download package.

image009

Find the directory where you created your project earlier with the React Native CLI. Inside that directory, extract the amazonaws folder from the Mobile Hub package archive you downloaded from Mobile Hub to android/app/src/main/java/com/amazonaws. Overwrite the existing directory (if it exists).

image010

Creating the React Native Android Module

Open projectname/android/app/build.gradle with a text editor and add the following dependencies. The Google Play library is required to use push notifications. The included badge library places a badge next to your push notifications.

dependencies {
compile fileTree(dir: "libs", include: ["*.jar"])
    compile "com.android.support:appcompat-v7:23.0.1"
    compile 'com.android.support:support-v4:23.1.0'
    compile "com.facebook.react:react-native:+"  // From node_modules
    compile "me.leolin:ShortcutBadger:1.1.4@aar"
    compile 'com.amazonaws:aws-android-sdk-core:2.3.9'
    compile('com.amazonaws:aws-android-sdk-pinpoint:2.3.9')
    compile('com.amazonaws:aws-android-sdk-apigateway-core:2.3.9')
    compile 'com.google.android.gms:play-services-gcm:7.8.0'
    compile 'com.google.code.gson:gson:2.7'
}

Create 3 new files in the android/app/src/main/java/com/pinpointsample package folder. Copy the contents of the files from the corresponding sample app repository files.

  • AWSMobileHubModule.java
  • AWSMobileHubPackage.java
  • AWSPushListenerService.java

Next, update your android/app/src/main/AndroidManifest.xml. Copy the contents from the sample app repository. If you did not use the example package name of com.pinpointsample, be sure to update the package names in the manifest file to your package name.

Note: The package names must match your application package name.

In the android/app/src/main/com/amazonaws/mobile/AWSConfiguration.java file, remove the “final” from all variables. These variables will be updateable from the JavaScript interface.

Note: If you update your Mobile Hub app in the future, you mustoverwrite the com.amazonaws.mobile package folder and will need to perform this step again if you want to be able to configure the variables from javascript.

Finally, modify the MainApplication.java file to load your new package. Add import com.pinpointsample.AWSMobileHubPackage; to the imports section of the class, then update the getPackages() method to include the module:

@Override
    protected List getPackages() {
      return Arrays.asList(
          new MainReactPackage(),
          new AWSMobileHubPackage()
      );
    }

Add your configuration to the constructor method in by copying the contents of the index.android.js from the sample code into your projects index.android.js. The values can be copied from your Mobile Hub generated AWSConfiguration.java file class (where you previously removed the “final” statement).

Finally, create a AWSMobileHub.js file in your projects root directory. this is the main interface that communicates with our native module. Copy the contents from the completed sample app repository file.

Note: the name of the module corresponds directly to the getName property inside the java module code getName() method.

Finally, enable the gradle daemon to speed up builds; run this command from your terminal on your Mac or Linux computer.

touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties

Now, run the app either on a device (push notifications may not work on the Android Emulator). From your root project run the following command:

react-native run-android
adb logcat

image011

The following information is logged to adb logcat:

Note: use the logcat.sh script in the sample app repository to automatically filter your adb logs with ./logcat.sh (on mac/linux) or just “logcat” on windows.

  • AWSMobileClient: AWS Mobile Client is OK – This means the AWS Mobile SDK was initiated
  • EventRecorder: Successful submission of 1 events – These events are being submitted to Pinpoint
  • TargetingClient: EndpointProfile – These are Amazon Pinpoint events

Within the app, when you choose the Request Weather button, you see a request to Amazon API Gateway. This request calls an AWS Lambda function, which simply returns the request. The app echoes the query parameter that was sent; in this case, the weather for the selected planet.

The API Gateway call can be used to send any request to API Gateway by passing in the method, endpoint, request body, and query params (see comments in the sample code). This call uses the Amazon Cognito identity, which in this example is an unauthenticated user. You can instead use a login system with an authenticated role and the SDK manages that for you. This call also sets custom attributes for the Weather Requested attribute so that you can engage with specific users that requested weather for a specific planet by creating a custom user segment within Amazon Pinpoint.

Next, choose Planet Trip, {COST}. The event echoes out in the adb log, which creates a monetization event using the AWS Mobile SDK. This event also updates custom attributes about this user under the Traveled To attribute, which enables you to engage with users who have traveled to this specific planet.

Enabling Campaign Management with Amazon Pinpoint

Next we are going to create user segments for each of the planet attributes users are interested in traveling to. Then we will create a campaign that targets these specific users based on their interests.

Go to the Amazon Pinpoint console and click on your app (if you used “PinpointSample” as the name of your Mobile Hub app, your Pinpoint app should be called “pinpointsample_MobileHub”), choose Segments, and then choose New Segment. Name your segment after a planet that you selected within the app; for example, “Earth People” if, in the app, you purchased a trip to Earth by clicking “Planet Trip”. Choose the + button under Custom Attributes, choose Planet and then choose Earth. This enables you to engage with all users that picked Earth in the app. You can also specify a usage metric; for example, Used within the last 30 days. The user count goes to 1 and shows 100%. This indicates that all current users are interested in this planet.

image013

Next, choose Campaigns, and then choose Create Campaign. Choose the segment that you created in the previous step by selecting Use a previously defined segment. For this example, the segment is called “Earth People”.

image014

The Segment estimate should be 1 total user. If the Segment estimate is 0, give it some time, refresh the app, and refresh the console. Be sure you see the Endpoint updated successfully event in the logcat log. If you are only running the app on the Android Emulator, try running it on a device instead.

Click Next step, choose Message and type a message. For example, in Title, type “Earth is Awesome”, and in Message, type “Travel to Earth now the weather is great!”

image015

Choose Next step.

image016

In the Advanced section, choose Immediate, and then choose Review and Launch. Choose Launch Campaign and return to the app running on your device. If the app is active the alert popup will display with your message. If your app is minimized, your notification appears in the top area of the screen with any other notifications. You can also see the update in the Amazon Pinpoint console. Tapping your notification will open your app. This behavior can be customized when you create the campaign within Amazon Pinpoint.

image017

Next, in the app, choose another planet. If your terminal is open, you should see a Endpoint updated successfully event display. Go back to the Amazon Pinpoint console. Choose Copy to new campaign. Choose Segment, choose Create a New Segment, and then choose Custom.

In “Customer Attributes” choose Planet and then choose the planet name you chose in the previous step. Repeat the preceding steps to send push notifications to this custom segment.

The custom attributes (attribute,value) can be changed in the index.android.js file’s _customAttributes function. The native module takes a simple comma delimited string as its argument for custom attributes, as follows.

  • @param {String} Attribute name i.e. “Interest”
  • @param {String} Attribute values i.e. “Pizza, Sushi”

You should also now see monetization events if you choose the Planet Trip, $200.00 button in the app. The monetization and usage data is populated in the Amazon Pinpoint console in near real time. When you choose the Planet Trip button in the app, the event is sent via Google Play monetization builder in the native AWS Mobile SDK. You can customize the values in index.android.js method via JavaScript. You can also customize and send more parameters by modifying the AWSMobileHubModule.java file to send details like Transaction ID. You simply need to update the generateMonetizationEvent method appropriately.

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

Source Code on GitHub
github.com/awslabs/aws-pinpoint-sample

Announcing the AWS SDK for React Native

by Rohan Deshpande | on | Permalink | Comments |  Share
We’re excited to announce the immediate availability of the developer preview of the AWS SDK for React Native. The source code is available on GitHub under the Apache 2.0 license.
 
The SDK includes support for the following services:
  • Amazon S3 to store user data, including photos and videos, in the cloud. It uses the TransferUtility, which simplifies file transfers between your app and the cloud.
  • Amazon DynamoDB to store data into a NoSQL database.
  • AWS Lambda to run serverless code in the cloud without the need for backend infrastructure.
  • Amazon SNS to send and receive push notifications.
The SDK core uses Amazon Cognito Identity as the authentication provider to comply with best practices for mobile app development.
 

Getting Started with the SDK

To include the SDK in your React Native application:
  1. Download the packages from Github.
  2. Add the services that you need into your package.json.
  3. Run npm install.
Here is a sample package.json that uses AWS Lambda. 
 
% cat package.json
{
  "name": "sample",
  "version": "0.0.1",
  "scripts": {
    "start": "node node_modules/react-native/local-cli/cli.js start"
  },
  "dependencies": {
    "aws-sdk-react-native-core": "../aws-sdk-react-native-core-0.0.1.tgz",
    "aws-sdk-react-native-lambda": "../aws-sdk-react-native-lambda-0.0.1.tgz",
    "react": "15.3.1",
    "react-native": "0.32.0"
  }
}
 	
See the GitHub repository for sample apps that demonstrate how to use the Cognito functionality to authenticate and the TransferUtility to transmit files to S3.
 

Contributing to the SDK

We welcome issue reports and contributions to the AWS SDK for React Native. Please report issues using the Github issue tracker. To contribute, submit a pull request to the GitHub repository with a description of your issue or suggested change. If this is a bug fix, please reference the issue and include steps to reproduce it.