Tag: iOS


How to Store Your App Photos in the Cloud Using Amazon S3 [tutorial and code samples]

by Dennis Hills | on | in AWS Mobile, CloudFront, Elastic Transcoder, HLS, Lambda, S3, Streaming Video | | Comments

About

Welcome to the first installment of our blog series showing how to build some of the most popular end-to-end experiences used by mobile apps. In each installment, you’ll see how you can build these experiences – including the client (iOS and Android) and the backend (AWS services) – in just a few minutes. We’ll typically use AWS Mobile Hub to accomplish this; Mobile Hub simplifies many of the steps you would normally have to go through, including authenticating users, securely configuring backend services, running backend code, and generating reference iOS and Android apps that use these features. We’ll then dive deeper, showing you how to integrate the experiences into your own applications and explaining what is happening within Mobile Hub.

Through the series, we’ll touch on a number of AWS services, including Amazon Cognito, Amazon S3, Amazon DynamoDB, and AWS Lambda. We welcome your suggestions in the comments for additional experiences or AWS services we should highlight!

Let’s get started with our first installment. This first post is about uploading photos to and downloading photos from the cloud from a mobile application. You’ll walk away with a fully functioning mobile application connecting to your AWS backend resources.

There are three steps in this tutorial.

Step 1. Configure the backend AWS resources via AWS Mobile Hub. This consists of creating a project, enabling a single feature called User Data Storage, and building/downloading the iOS Swift sample app source code project.

Step 2. Explore uploading to and downloading photos from Amazon S3 using the sample app generated by Mobile Hub.

Step 3. Store and Retrieve Photos from your own app by following the AWS Mobile Hub integration guide customized for your project.

First, we’ll explain briefly what Mobile Hub is and the AWS features (Amazon S3 and Amazon Cognito Identity) that we’ll enable within a Mobile Hub project.

What is AWS Mobile Hub
AWS Mobile Hub simplifies the process of building, testing, and monitoring mobile applications that make use of one or more AWS services. It can help you skip the front- and back-end heavy lifting of manually creating cloud service configurations and integrating them into your client.  The mobile app features supported includes user authentication, data storage, backend logic, push notifications, content delivery, and analytics—all from a single, integrated console.

There is no charge for Mobile Hub; you only pay for the AWS services used. For example, after you complete this tutorial, you are only charged for the objects stored in your S3 bucket. Learn more about AWS Mobile Hub features.

What is Amazon Cognito Federated Identity
Amazon Cognito Federated Identities enable you to create unique identities for your users and authenticate them with identity providers. With an identity, you can obtain temporary, limited-privilege AWS credentials to synchronize data with Amazon Cognito Sync, or directly access other AWS services. Amazon Cognito Identity supports public identity providers—Amazon, Facebook, Google, and SAML identity providers—as well as unauthenticated identities, which is what we’ll be utilizing in this tutorial. Learn more about Amazon Cognito Federated Identities.

What is Amazon S3
Amazon Simple Storage Service (Amazon S3) provides secure, durable, highly scalable object storage in the cloud. Using the AWS Mobile SDK, you can directly access Amazon S3 from your mobile app. The AWS Mobile SDK allows you to consume the Amazon S3 service in your mobile application via the S3 Transfer Utility. The fully functional iOS sample app generated by Mobile Hub includes the AWS Mobile SDK for iOS, S3 Transfer Utility, and all the helper code for running the demo app used for this tutorial. Learn more about Amazon S3 cloud storage and pricing.

Let’s Begin

Step 1 – Configure the backend

We’ll use Mobile Hub to create a project and then enable the User Data Storage feature to store and retrieve photos from Amazon S3. We walk you through the steps and follow up with a recap (explain the magic) of what just happened.

1)  Launch AWS Mobile Hub console

2)  Select Create new mobile project.

3)  Provide a project name, S3Blog, and then select Create project.


Note: If you have never used Mobile Hub before, you’ll be prompted to select Get Started and Yes, grant permissions before you can create a new project.

4)  Select User Data Storage.


5)  Select Store user data and then choose Save changes.


6)  Select Integrate from the left panel


7)  From the integration tab, make sure iOS Swift is selected and that you are in the Getting Started section.
8)  Select Download a sample app to download your iOS Swift project source code (zipped project folder). We’ll run this project in Xcode in just a minute.

Done. You now have all your AWS resources configured and the custom-built iOS Swift source code project is downloaded and ready.

What did we just do?

First, we created a new project in AWS Mobile Hub. Note that, for each Mobile Hub project created, an Amazon Cognito identity pool is created on your behalf, regardless of what features are enabled. Amazon Cognito Identity is being used in our app to obtain temporary, unauthenticated, limited-privilege credentials to directly access Amazon S3 from a mobile app.

In a future blogpost, we’ll discuss the Mobile Hub User Sign-in feature where Amazon Cognito provides authenticated identities through Amazon Cognito User Pools and public identity providers—Amazon, Facebook, Google, and SAML. for this tutorial, just know that we’ll be using Amazon Cognito unauthenticated identities to demonstrate this topic.

After the project was created with the default Amazon Cognito identity pool, you then enabled the User Data Storage feature in your Mobile Hub project. This feature first creates an Amazon S3 bucket to store user photos and creates a policy within the AWS Identity and Access Management (IAM) role that grants your user’s access to Amazon S3 when they launch the app. Within the S3 bucket, a /Public folder was created with access permissions set to allow all users of your app to view and upload files stored there. There’s also a /Private folder created, which we’ll discuss in the next blog post. This folder is used to store private data for each user when authenticated through the User Sign-in feature of Mobile Hub.

Here’s how the sample app works:

The user launches the app and immediately that user is given a unique unauthenticated Amazon Cognito Identity. The user then selects the User Data Storage demo feature to upload a photo from his or her photo library to the /Public folder within the S3 bucket. The unique unauthenticated Amazon Cognito Identity given to that user provides limited-privilege credentials to directly access the /Public folder of your S3 bucket.

Now that we have created file storage that is designed for scalability, let’s go demo the app!

Step 2 – Running the Sample APP

Now for the fun part. In the previous step 1, you configured the AWS resources you needed, built the sample app project code, and downloaded it to your Mac. At the end of this walkthrough, we’ll go into how Mobile Hub guides you in integrating these features into your own app.

For now, we’ll now describe how to open the sample project code in Xcode and run the iOS sample app on a physical iOS device or simulator. It’s that simple.

The iOS sample app provides a demo for retrieving files from your S3 bucket and uploading photos from your iOS device photo library. Mobile Hub has placed a sample image to get started.

1) Unzip the iOS Swift project code you downloaded previously

step2-1

2) Open the sample app project in Xcode by double-clicking on the Xcode project, MySampleApp.xcodeproj, which is in the project folder.

3) Select build/run within Xcode to build and run the sample app.

When the sample app is first launched, a function called is called to retrieve an ID generated by the Amazon Cognito Identity service. The function invokes that manages access to Amazon Cognito. The following method illustrates how to retrieve an app user’s identity

4) At the main screen of the sample app, select User Data Storage and then Demo User File Storage feature.

step2-4a     step2-4b

You are now in the User File Storage demo and you’ll see example-image.png, which Mobile Hub provided to get started. You can now download the example image from Amazon S3 to your device.

5) To download an image from the list, select the file and then choose Download from the action item list as shown.

step2-5

Here’s the sample function that is used to download files from Amazon S3 to the mobile app.

You should now see a green check mark next to the example image, which indicates that it has been downloaded from Amazon S3 and cached locally in the app.

Now you can upload an image to Amazon S3 from your camera roll.

6) To upload a photo from your photo library to Amazon S3, select the action icon on the upper right of the screen and then choose Upload from within the User File Storage demo of the sample app.

user-storage-upload-1

7) The app will request access to your photo library. Select OK.

step2-7

8) Now the app has access to your camera roll and you can select a photo to upload to Amazon S3. Here, you can select a waterfall image.

step2-8

9) After you select an image, you are prompted to give your file a name. Give it a name and make sure you add .png to the end as shown so the app can recognize this as an image. Select Done and you’ll see the activity indicating the image is being uploaded to Amazon S3.

step2-9a   step2-9b

After the image upload completes, it’ll show in the list but without the green check mark, which indicates it’s now in the cloud (stored in your S3 bucket) but not cached locally in the app.

Here’s the sample iOS Swift function code used for uploading images from your app to Amazon S3.

What did we just do?
We just provisioned AWS backend resources consisting of an Amazon Cognito ID and Amazon S3 bucket using AWS Mobile Hub. We then built and launched the generated sample app. The app demonstrates the User Data Storage feature by uploading photos from your iOS device to Amazon S3 and downloading photos from Amazon S3 to your iOS device.

Are you done playing? We hope you enjoyed this tutorial. Stay tuned for the next installment where we’ll build on this idea and add user sign-in for more private storage and user data sync.

Are you interested in looking behind the curtain? To see that image you uploaded in the S3 bucket that was created for you, choose the Resources button on the left-hand navigation of the Mobile Hub console, choose the link in the tile labeled Amazon S3 buckets to open the Amazon S3 console, then choose the Public folder.

Planning to integrate this feature into your own app? No problem! In step 3, next, we’ll walk you through the Mobile Hub integration guide, helping you integrate all the code from the sample app into your own app.

Step 3 – Store and retrieve photos from your own app

You just configured a backend file storage and ran our generated sample app to demonstrate the end-to-end functionality of this common mobile feature. However, what you really need is the same functionality in your own app. Mobile Hub provides integration instructions specific to each mobile project you create. Let’s get started.

Go back to your Mobile Hub project in the console and select Integrate. The integration instructions from Mobile Hub will first walk you through Getting Started and then describe each feature you enabled in your Mobile Hub project and how to integrate each of them into your own app.

Here’s a quick overview of Getting Started and additional instructions for integrating this project into your own application.

The Mobile Hub Getting Started integration instructions include:

Download the Mobile SDK for iOS and custom source code provided

  • The download provides the latest SDK, Mobile Hub helper code, and example source code to get you started.

  • After downloading the SDK and helper code, drag and drop the Sdk folder contained in the download into your own project within Xcode. This assumes you already have an iOS Swift project of your own; if not, create a new one and follow along.
  • Add the AWS SDKs as Embed Frameworks.
  • Add Run Script phase to your project as directed.
  • Copy the AmazonAws folder from the helper code to your project and add a group for it. This source code contains a customized helper framework that simplifies the use of all the SDKs that are required to support your project.It also contains the AWSMobileClient.swift file, which bootstraps the app and creates an identity manager to establish the user identity with Amazon Cognito.
  • Copy the AWS dictionary from the integration Info.plist into your own project Info.plist. The AWS dictionary provides the CognitoIdentity poolId and region for your project.
  • Add AWS iOS SDK dependencies, libsqlite3.tbd and libz.tbd, under Linked Frameworks and Libraries as directed.
  • Set up your Application Delegate by returning the AWSMobileClient singleton as shown:
    You are now done with the Getting Started section.

After you complete Getting Started, you can then select User Data Storage in the left panel of the integration instructions. Here, you just need to do the following:

  • Copy the AWS dictionary from the integration Info.plist into your own project Info.plist. The AWS dictionary already provides all the CognitoIdentity pool IDs for your project as well as the S3 bucket and region.
  • View or copy the example upload/download source code provided. The idea is to use this code in your own UIViewController.

That’s it! You should now be able to run your own application and connect it to your AWS resources like we demonstrated using the sample app generated by AWS Mobile Hub.

Conclusion

We just configured a backend data storage feature via AWS Mobile Hub, generated a fully functional sample iOS app demonstrating uploading and downloading photos to and from S3, and then walked through integrating the client code into your own app, connecting to the same backend resources demonstrated in the sample app.

Thanks and happy coding!

Announcing the AWS SDK for React Native

by Rohan Deshpande | on | | Comments
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.

 

Test User Interfaces in iOS Apps with XCTest UI and AWS Device Farm

by Asha Chakrabarty | on | | Comments

With AWS Device Farm, you can quickly start testing your Android, iOS, and FireOS apps on real devices in the AWS Cloud. Choose to start an interactive session with a device or run automated tests on many devices at once. AWS Device Farm will provide the results of your tests including pass/fail status, logs, performance metrics, screenshots, and videos.

Introduction to XCTest UI

As of Xcode 7, you can access UI testing capabilities (XCUI) integrated into the Xcode IDE. This functionality allows you to find and interact with UI elements in your app and confirm their properties and states. A few new features make it possible for you to programmatically test and exercise the UI of an iOS app with:

  • New Xcode target type for UI tests:

To set up a UI test in Xcode, you create an Xcode target with the iOS UI Testing Bundle template. The Xcode target type fulfills the special requirements required by the UI tests, including launching a proxy for the application in a separate process and providing accessibility permissions.

  • UI testing APIs include three key classes:

    • XCUIElementQuery: Every UI element is backed by the ability to query its properties. For this reason, each XCUIElement must be unique.
    • XCUIElement: A proxy object for a UI element that is represented as types (for example, a cell or a button).
    • XCUIApplication: An instantiation of your application object that forms the origin for finding UI elements.
  • UI recording:

This allows you to record interactions with your app’s user interface. Xcode will transform these interactions into source code that can be included in your existing tests or to create new tests. 

AWS Device Farm now allows you to run the UI Testing feature incorporated in Xcode 7 on real devices in the AWS Cloud. In this post, we will walk you through how to create an XCTest UI test, package it for testing on AWS Device Farm, schedule a run, and view test results from real devices in the cloud.

Prerequisites

  • You’ll find the sample iOS app used in this post on AWS Labs on GitHub.
  • UI Testing was introduced in Xcode 7 and iOS 9, so be sure to update accordingly.
  • iOS devices must be enabled for development and connected to a host running Xcode.
  • It is assumed that you have created the .ipa file for the sample iOS app before you schedule a run in AWS Device Farm.

Step 1: Create a UI Test for the AWS Sample iOS App

After you have downloaded and opened the sample app in Xcode, build the project. After the build is successful, you will create a new a target type for the UI tests.

Your project navigator should look like the following:

With UI testing, you can record interactions within your app and Xcode will write the code required to re-enact those interactions in your test. You will still need to use XCTAssert to add your test assertions. You can record interactions with your UI by pressing the record button (the small red dot at the bottom left corner of the editor pane).

Copy the following UI test code to your AWSDeviceFarmiOSReferenceAppUITests.m implementation file.

#import 

@interface AWSDeviceFarmiOSReferenceAppUITests : XCTestCase

@end

@implementation AWSDeviceFarmiOSReferenceAppUITests

- (void)setUp {
    
    [super setUp];
    self.continueAfterFailure = NO;
    [[[XCUIApplication alloc] init] launch];
    
}


- (void)tearDown {
    
    [super tearDown];
}


- (void)testNativeInput {
    
    XCUIApplication *app = [[XCUIApplication alloc] init];
    XCUIElementQuery *tabBarsQuery = app.tabBars;
    [tabBarsQuery.buttons[@"Native"] tap];
    
    XCUIElementQuery *collectionViewsQuery = app.collectionViews;
    [collectionViewsQuery.staticTexts[@"Table of elements"] tap];
    [app.navigationBars[@"ElementsTableView"].buttons[@"Menu"] tap];
    [collectionViewsQuery.staticTexts[@"Scrolling View"] tap];
    [app.navigationBars[@"Scrolling View"].buttons[@"Menu"] tap];
    [tabBarsQuery.buttons[@"Home"] tap];
    
}


- (void)testNestedView {
    
    
    XCUIApplication *app = [[XCUIApplication alloc] init];
    XCUIElementQuery *tabBarsQuery = app.tabBars;
    [tabBarsQuery.buttons[@"More"] tap];
    [app.staticTexts[@"Nested"] tap];
    
    XCUIElement *moreNavigationBar = app.navigationBars[@"More"];
    XCUIElement *nextButton = moreNavigationBar.buttons[@"Next"];
    [nextButton tap];
    [nextButton tap];
    [nextButton tap];
    
    XCUIElement *backButton = [[[moreNavigationBar childrenMatchingType:XCUIElementTypeButton] matchingIdentifier:@"Back"] elementBoundByIndex:0];
    [backButton tap];
    [backButton tap];
    [backButton tap];
    [moreNavigationBar.buttons[@"More"] tap];
    [tabBarsQuery.buttons[@"Home"] tap];
    
}


- (void)testAlertControl {
    
    
    XCUIApplication *app = [[XCUIApplication alloc] init];
    XCUIElementQuery *tabBarsQuery = app.tabBars;
    [tabBarsQuery.buttons[@"More"] tap];
    [app.staticTexts[@"Alerts"] tap];
    [app.buttons[@"Modal"] tap];
    [app.buttons[@"OK"] tap];
    [app.buttons[@"Alert"] tap];
    [app.alerts[@"Alert"].collectionViews.buttons[@"OK"] tap];
    [app.navigationBars[@"More"].buttons[@"More"] tap];
    [tabBarsQuery.buttons[@"Native"] tap];
    [app.collectionViews.staticTexts[@"Image Gallery"] tap];
        
}

@end

Before packaging your test for AWS Device Farm, be sure to build the project with Xcode. Use the Product/Build for Running option select an iOS device. Keep in mind that the Build Active Architecture setting for your app and your UI test targets should be the same.

Step 2: Package Your Test for AWS Device Farm

When packaging your test for upload to AWS Device Farm, make sure your iOS XCTest UI Runner test runner bundle is contained in a correctly formatted .ipa file. For more information, see the AWS Device Farm documentation. You can also view the creation of an .ipa file on AWS Labs on GitHub.

Make sure that you package your test in the Payload folder under debug-iphoneos as shown here. In the following screenshot, we renamed the resulting zip file of the Payload folder to UITest.ipa for easier file management.

Step 3: Schedule a Run in AWS Device Farm

Sign in to the AWS Device Farm console and create a run under a new or existing project. Upload the .ipa file of the sample app.

In the next step, you will choose XCTest UI as the test type and upload the .ipa file you created in step 2.

Select the devices on which you’d like to test. If you like, you can create a new device pool for your test run to reuse in subsequent runs.

Finally, review and start the test run.

Step 4: View XCTest UI Test Results

When your test run is complete, you will see the test results summary.

Choose a device to examine its test suites. Here we are reviewing the test suite results for an Apple iPhone 5s and Apple iPhone 6 device.

The results for each device will contain screenshots, video recordings, performance data, and log files that can be downloaded for further review.

Conclusion

We are always happy to hear your feedback. Feel free to leave your feedback, including questions, in the comments or on our developer forum.

Happy testing!

Test iOS apps on AWS Device Farm using Appium – Part 3: Upload your iOS Application and TestNG tests to AWS Device Farm

by Asha Chakrabarty | on | | Comments

With AWS Device Farm, you can quickly get started testing your Android, iOS, and FireOS apps on real devices in the AWS cloud. Simply upload your app, choose your test framework and the devices you want to test your app on, and start your test run. AWS Device Farm will provide the results of your tests including pass / fail status, logs, performance characteristics, and screenshots.

Previously in Part 1 and Part 2 of this series, you set up your environment, created and validated your TestNG tests, and packaged your TestNG tests for upload to AWS Device Farm. In Part 3, you will upload the sample iOS app (an unsigned ipa file you downloaded as part of the prerequisities section in Part 1) and the TestNG package you created in Part 2.

Upload the sample iOS app and TestNG suite to AWS Device Farm

We now have the sample iOS app (ToDoList.ipa) you downloaded and the TestNG package (zip-with-dependencies.zip) that contains our test code and test dependencies. To begin testing iOS apps on AWS Device Farm, you will need an .ipa (iOS app archive) file, which you will upload to AWS Device Farm. Make sure when you create your own iOS apps, your .ipa file is built for an iOS device and not for a simulator. You do not need to add any UDIDs to your profile as Device Farm will resign your app automatically (See the FAQ for more info).

Follow the Getting Started steps to begin testing with AWS Device Farm. You will upload the iOS app (.ipa file), configure your test type (choose Appium with TestNG), and upload the zip-with-dependencies file that was created as part of the Maven build in Part 2 of this series.

Log into your AWS Account and navigate to the AWS Device Farm console under the Mobile Services category.

Create a new project if you do not have an existing one. A project is a logical workspace for your test runs.

Once you have created a project, click on it and create a run. A run represents a test of a specific build of your app, with a specific set of tests, to be run on a specific set of devices. Each test run will produce a report containing information about the results of the run. 

Browse to the location of the ipa file you downloaded in Part 1 and upload.

Once the app has successfully uploaded, proceed to configure the test type. For this example, we will select Appium Java TestNG. Note that the Appium Java TestNG framework is currently in preview mode. 

Upload the zip-with-dependencies zip file that was created in Part 2 of this series. This can be found in the “target” folder of the Maven project in the workspace location where you have stored your Eclipse projects.

Select the devices that are compatible with the app for testing. For this example, we will use a curated list of devices called Top Devices that AWS Device Farm has pre-selected for us. You have the option of selecting other devices by creating a new device pool.

The next step prompts you to specify device states to override any device settings. This allows you to provide additional data and / or install additional apps for AWS Device Farm to use during the run, specify whether Wi-Fi, Bluetooth, GPS, or NFC will be enabled during the run, preset the device latitude and longitude for the run, and preset the device locale for the run.

Choose "Review and start run." On the Review and start run page, choose "Confirm and start run" once you have confirmed all details. When your tests have completed, you will be able to drill down into each device to view the results.

If we click on the first device (Apple iPhone 5c), we can see that our TestNG test suites passed successfully and how much time it took for each to complete.

Based on the TestNG test suite we created in Part 1, you can see that each method that is part of the "com.aws.devicefarm.example.appiumiostest.SampleAppiumTestNGTest" package has been executed. Further if we click on the package name, you will see the four test cases that were created using the Appium Inspector. For each test case, you can view associated screenshots and download log files.

When you click on the "Screenshots" tab, any screenshots that were included in "test01" will be seen.

When you go to the "Files" tab, you will see a list of log files that have been generated for the "test01" test. You can click on each log file and download it for review.

Summary

By utilizing AWS Device Farm, you can test your iOS apps across multiple devices in parallel and get results in minutes to quickly understand your app’s behavior on popular devices. Now that you have an understanding of the steps involved in testing your iOS apps with Appium on AWS Device Farm, I’d highly encourage you to begin testing your own iOS apps. No modifications are required to your app or test code – just package your tests, upload, and start testing!

If you have questions or comments, please reach out to us in the comments section below or on our developer forum. We are happy to receive your feedback on AWS Device Farm and how to make testing iOS apps more seamless for you.

Happy Testing!

Test iOS apps on AWS Device Farm using Appium – Part 2: Packaging your TestNG test suite for AWS Device Farm

by Asha Chakrabarty | on | | Comments

With AWS Device Farm, you can quickly get started testing your Android, iOS, and FireOS apps on real devices in the AWS cloud. Simply upload your app, choose your test framework and the devices you want to test your app on, and start your test run. AWS Device Farm will provide the results of your tests including pass / fail status, logs, performance characteristics, and screenshots.

Previously in Part 1, we focused on the prerequisites and creation of the TestNG test suite. In this article, Part 2 of the three-part series, we will walk through how to package your test suite for uploading to AWS DeviceFarm. Before uploading your test suite to AWS Device Farm, the test suite should be packaged correctly and contain all the required dependencies. Both the tests and associated dependencies must be packaged as a zip file. In Part 3, we will upload the package from this post and run the tests on AWS Device Farm.

Package your TestNG Test Suite

Create a new Maven project in Eclipse using the quickstart archetype (maven-archetype-quickstart). It is recommended to match the Group Id / Artifact Id with the root package as shown in the sample pom.xml. For this sample, our package name is com.aws.devicefarm.example.appiumiostest.

Copy the TestNG class created in the previous step to your Maven project under src/test/java.

Save the following XML assembly to src/main/assembly/zip.xml. The following XML is an assembly definition that, when configured, instructs Maven to build a .zip file containing everything in the root of your build output directory and the dependency-jars directory.

	<assembly

	    xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0"

	    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

	    xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">

	      <id>zip</id>

	      <formats>

	            <format>zip</format>

	      </formats>

	      <includeBaseDirectory>false</includeBaseDirectory>

	      <fileSets>

	            <fileSet>

	                  <directory>${project.build.directory}</directory>

	                  <outputDirectory>./</outputDirectory>

	                  <includes>

	                    <include>*.jar</include>

	                  </includes>

	            </fileSet>

	            <fileSet>

	                  <directory>${project.build.directory}</directory>

	                  <outputDirectory>./</outputDirectory>

	                  <includes>

	                    <include>/dependency-jars/</include>

	                  </includes>

	            </fileSet>

	      </fileSets>

	</assembly>

Replace your pom.xml with the following (NOTE: Change the groupId, artifactId, and name elements to match that of your Maven project).

	<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

	  <modelVersion>4.0.0</modelVersion>

	

	  <groupId>com.aws.devicefarm.example</groupId>

	  <artifactId>appiumiostest</artifactId>

	  <version>0.0.1-SNAPSHOT</version>

	  <packaging>jar</packaging>

	  <name>appiumiostest</name>

	  <url>http://maven.apache.org</url>

	

	  <properties>

	    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>

	  </properties>

	  <dependencies>

	        <dependency>

	            <groupId>org.testng</groupId>

	            <artifactId>testng</artifactId>

	            <version>6.8.8</version>

	            <scope>test</scope>

	        </dependency>

	        <dependency>

	            <groupId>org.seleniumhq.selenium</groupId>

	            <artifactId>selenium-java</artifactId>

	            <version>2.42.2</version>

	        </dependency>

	        <dependency>

	            <groupId>io.appium</groupId>

	            <artifactId>java-client</artifactId>

	            <version>1.4.0</version>

	        </dependency>

	  </dependencies>

	  <build>

	        <plugins>

	            <plugin>

	                <groupId>org.apache.maven.plugins</groupId>

	                <artifactId>maven-jar-plugin</artifactId>

	                <version>2.6</version>

	                <executions>

	                    <execution>

	                        <goals>

	                            <goal>test-jar</goal>

	                        </goals>

	                    </execution>

	                </executions>

	            </plugin>

	            <plugin>

	                <groupId>org.apache.maven.plugins</groupId>

	                <artifactId>maven-dependency-plugin</artifactId>

	                <version>2.10</version>

	                <executions>

	                    <execution>

	                        <id>copy-dependencies</id>

	                        <phase>package</phase>

	                        <goals>

	                            <goal>copy-dependencies</goal>

	                        </goals>

	                        <configuration>

	                            <outputDirectory>${project.build.directory}/dependency-jars/</outputDirectory>

	                        </configuration>

	                    </execution>

	                </executions>

	            </plugin>

	            <plugin>

	                <artifactId>maven-assembly-plugin</artifactId>

	                <version>2.5.4</version>

	                <executions>

	                    <execution>

	                        <phase>package</phase>

	                        <goals>

	                            <goal>single</goal>

	                        </goals>

	                        <configuration>

	                            <finalName>zip-with-dependencies</finalName>

	                            <appendAssemblyId>false</appendAssemblyId>

	                            <descriptors>

	                                <descriptor>src/main/assembly/zip.xml</descriptor>

	                            </descriptors>

	                        </configuration>

	                    </execution>

	                </executions>

	            </plugin>

	        </plugins>

	  </build>

	</project>

Build, package, and verify your Maven project using the following command.

mvn clean package –DskipTests=true

The Maven project structure should look similar to the below. Note the zip-with-dependencies file that was created under the “target” folder. This contains our test code with all dependencies:

Summary

Now that we have packaged our tests and have a sample iOS app to test, in Part 3 we will upload both to AWS Device Farm to test across multiple devices and receive test results within minutes. Feel free to post any suggestions, comments or questions in the comments section below or in our developer forum. We look forward to hearing your feedback.

Test iOS apps on AWS Device Farm using Appium – Part 1: Prerequisities, Environment Set Up, and Test Creation

by Asha Chakrabarty | on | | Comments

With AWS Device Farm, you can quickly get started testing your Android, iOS, and FireOS apps on real devices in the AWS cloud. Simply upload your app, choose your test framework and the devices you want to test your app on, and start your test run. AWS Device Farm will provide the results of your tests including pass / fail status, logs, performance metrics, and screenshots.

The objective of this three-part series is to walk through step-by-step how to get started testing an iOS app with AWS Device Farm. The test automation framework we will be using is Appium and we will write our test cases using the TestNG framework. We will not be building an iOS app as part of this walkthrough. However, to follow along with this post, a sample iOS app is available for download here.

At the end of this series, you will have the knowledge required to test an iOS app with AWS Device using Appium and TestNG.

Prerequisites

For this example, the tools and versions listed below were used. It is assumed you have these tools installed on your machine beforehand and that you have an AWS Account.

  • Java 8
  • Eclipse IDE Mars was used for this tutorial.
  • m2e Maven Integration for Eclipse
  • Xcode 7.0 We will use a sample, unsigned iOS app called “ToDoList.ipa” that you can download here.
  • Appium 1.4.8 If you have not worked with Appium before, please review the Appium documentation before moving ahead.  We will be using the Appium GUI for this tutorial.  Please install the latest version of the Appium GUI.
  • Apache Maven 3.3.3 Or the latest version of Maven
  • AWS Account and IAM User creation Follow steps under the Setting Up section of the AWS Device Farm documentation.

A preamble on Appium

Appium is a test automation framework that executes your test suite across both iOS and Android apps without you having to further modify your app or create separate test suites for the same app. Appium is able to provide this capability by utilizing Selenium WebDriver, which follows a client-server protocol. Appium uses Selenium WebDriver to be able to receive commands from a client running your tests and respond to those commands with a response over HTTP. This follows a request / response paradigm in which requests are the commands being sent to the Appium server and responses are being received by the client via WebDriver. 

Appium executes your tests as described below:

  1. Tests for an iOS or Android app are written in a WebDriver-supported programming language. Appium provides client-side libraries for many languages. 
  2. An Appium server is launched after installation and configuration on the test machine.
  3. The tests are initiated on a client machine.
  4. Appium will begin receiving commands from the client (the machine running your tests) and execute those commands (your test emulating user actions with your app) on an emulator or real device.

Now that we have walked through the prerequisites and an overview of Appium, let’s get started building out our test cases for the sample iOS app you have downloaded.

Create a Java project in Eclipse

Launch Eclipse and create a new Java project to begin writing your test cases by selecting File -> New -> Java Project.

Create two source folders: src/main/java and src/test/java. Within each source folder, create a package in which you will eventually create your TestNG test class. Your project structure should look similar to the below.

Configure the build path for each source folder by right clicking the source folder and selecting ‘Configure Build Path.’ Ensure you have selected the Java Build Path option from the left hand menu and you are on the Source tab. Check the ‘Allow output folders for source folders’ option.

  1. For src/main/java -> the output folder is target/classes.
  2. For src/test/java -> the output folder is target/test-classes.

The build paths for your source folders should look similar to the folders in the image below.

Add external libraries for Selenium WebDriver, TestNG, and Appium Java Client

Selenium

Download the Selenium Client & WebDriver Language Bindings for the language of your choice. For this tutorial, we will be using Java.  Downloads are available at: http://docs.seleniumhq.org/download/.

  1. Once you have saved and unzipped the Selenium dependencies to your machine, right-click the Java project created in Step 1 and go to Properties.  
  2. Select Java Build Path in the left-hand menu and ensure you are on the Libraries tab. Select ‘Add External JARS’ and navigate to the location of your Selenium jar files. 
  3. Select the 2 Selenium jar files and the jar files in the folder ‘libs’ and click ‘Apply.’

TestNG

To install TestNG in Eclipse, go to Help -> Eclipse Marketplace -> Search for TestNG and Install.

Once you have installed TestNG in Eclipse, proceed below:

  1. Right click on the project created in Step 1 and go to Properties. 
  2. Select Java Build Path in the left-hand menu and ensure you are on the Libraries tab. Select the ‘Add Library’ button on the right.
  3. Select TestNG -> Next -> Finish.
  4. Select ‘Apply’ and then click OK.

Appium client for Java

Download the Appium client library for Java and add the jar file to the project you created in Step 1. Follow steps as performed when adding the Selenium jar files.

Once all referenced libraries have been added to your Java project, your project structure should look similar to the image below.

Create the TestNG test suite

Create a Java class called "SampleAppiumTestNGTest" under src/test/java for creating your TestNG test code. Paste the below sample TestNG code:

package com.aws.devicefarm.example.appiumiostest;

import org.testng.annotations.Test;
import java.io.File;
import java.net.URL;
import org.openqa.selenium.By;
import org.openqa.selenium.OutputType;
import org.openqa.selenium.TakesScreenshot;
import org.openqa.selenium.remote.DesiredCapabilities;
import org.openqa.selenium.remote.RemoteWebDriver;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;

public class SampleAppiumTestNGTest 
{
	private static RemoteWebDriver driver = null;
	
	public boolean takeScreenshot(final String name) {
		String screenshotDirectory = System.getProperty("appium.screenshots.dir", System.getProperty("java.io.tmpdir", ""));
		File screenshot = ((TakesScreenshot) driver).getScreenshotAs(OutputType.FILE)
		return screenshot.renameTo(new File(screenshotDirectory, String.format("%s.png", name)));
	}
  
	
	@BeforeMethod
	public void setUp() throws Exception {
		DesiredCapabilities capabilities = new DesiredCapabilities();
       		URL url = new URL("http://localhost:4723/wd/hub");
        	driver = new RemoteWebDriver(url, capabilities);
	}
	
	
	@Test
	public void test01() throws InterruptedException {
		driver.findElement(By.name("Add")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATextField[1]")).sendKeys("Complete Taxes");
		driver.findElement(By.name("Save")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[4]")).click();
		String screenshot1 = null;
		takeScreenshot(screenshot1);
	}
	
	
	@Test
	public void test02() throws InterruptedException {
		driver.findElement(By.name("Add")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATextField[1]")).sendKeys("Book tickets for vacation");
		driver.findElement(By.name("Save")).click();
		String screenshot2 = null;
		takeScreenshot(screenshot2);
	}
	

	@Test
	public void test03() throws InterruptedException {
		driver.findElement(By.name("Add")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIANavigationBar[1]/UIAButton[1]")).click();
	}
	

	@Test
	public void test04() throws InterruptedException {
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]")).click();
		driver.findElement(By.xpath("//UIAApplication[1]/UIAWindow[1]/UIATableView[1]/UIATableCell[1]")).click();
	}

	
	@AfterMethod
	public static void tearDownClass() {
        		if (driver != null) {
            		driver.quit();
        		}
    	}
}

To capture the user interface elements and interactions in the TestNG test suite, Appium Inspector was used. To do this yourself, you can launch the Appium GUI and select the iOS Settings.

  1. For the App Path, navigate to the location of your .app file. 
  2. Ensure you check the Force Device option and choose a device.
  3. Ensure a Platform Version is selected.
  4. Click the Launch button.
  5. Click the icon with the magnifying glass to launch the Appium Inspector.
  6. Begin recording your tests.

NOTE:  Appium versions 1.4.11 and later support Xcode 7 with iOS 9 simulators. To use the Appium Inspector for capturing elements in this case, you will need to point the Appium client GUI to the latest Appium version. To do this:

  1. Clone the Appium git to your local git clone (https://github.com/appium/appium.git)
  2. Once the download is complete, Run reset.sh
  3. Open the Appium client (GUI)
  4. Select "Developer settings" and enable it
  5. Select Use External NodeJS Binary to "Your local node bin folder path"
  6. Select Use External Appium Package to "Your Appium Local clone folder path"
  7. Launch the Appium Server

Summary

You should now have your environment set up, a sample iOS app that you downloaded, and an Eclipse project with your TestNG tests.  With this you can run your test suite locally with Appium and validate your tests. Join us in Part 2 where we will walk through how to prepare your TestNG test suite for uploading to AWS Device Farm. Finally, in Part 3 we will run the tests we’ve created in the AWS Cloud with AWS Device Farm. We are always interested in your feedback, comments, and questions so please reach out to us in the comments section below or in our developer forum.

 

Preparing Your Apps for iOS 9

by Yosuke Matsuda | on | | Comments

The release of iOS 9 includes changes that could impact how your apps interact with some AWS services. If you compile your apps with Apple’s iOS 9 SDK (or Xcode 7), Apple’s new App Transport Security (ATS) feature may affect your apps’ ability to connect to certain AWS service endpoints. In order to ensure your apps continue to successfully connect to AWS endpoints, you’ll need to configure them to interact properly with Apple’s ATS by adding the following properties to your Info.plist file:

<key>NSAppTransportSecurity</key>
<dict>
      <key>NSExceptionDomains</key>
      <dict>
            <key>amazonaws.com</key>
            <dict>
                  <key>NSThirdPartyExceptionMinimumTLSVersion</key>
                  <string>TLSv1.0</string>
                  <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
                  <false/>
                  <key>NSIncludesSubdomains</key>
                  <true/>
            </dict>
            <key>amazonaws.com.cn</key>
            <dict>
                  <key>NSThirdPartyExceptionMinimumTLSVersion</key>
                  <string>TLSv1.0</string>
                  <key>NSThirdPartyExceptionRequiresForwardSecrecy</key>
                  <false/>
                  <key>NSIncludesSubdomains</key>
                  <true/>
            </dict>
      </dict>
</dict>

If you are not planning to recompile your apps with Apple’s iOS 9 SDK (or Xcode 7) to run on iOS 9 devices, you do not need to make any configuration changes.

References:

Amazon S3 Transfer Utility for iOS

by Yosuke Matsuda | on | | Comments

Amazon S3 Transfer Manager for iOS was designed to simplify the data transfer between your iOS app and Amazon S3. It is one of the most used components in our SDK. Two of the most requested features from our developer are 1) the ability to continue transferring data in the background 2) an API to upload binary data instead of having to first save it as a file.

Today we are pleased to announce the introduction of an easier and more powerful way to transfer data between your iOS app and Amazon S3: the Amazon S3 Transfer Utility for iOS (beta). In this blog post, I will show you how to get started with the new Amazon S3 Transfer Utility.

Setup

Amazon Cognito Identity

First, you need to set up Amazon Cognito Identity.

Objective-C

  1. Import the <AWSS3/AWSS3.h> header in your application delegate class.

     #import <AWSS3/AWSS3.h>
    
  2. Set up AWSCognitoCredentialsProvider in the - application:didFinishLaunchingWithOptions: application delegate.

     - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
         AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1
                                                                                                         identityPoolId:@"YourIdentityPoolId"];
         AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1
                                                                              credentialsProvider:credentialsProvider];
         AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
    
         return YES;
     }
    

For more information, see the Set Up the SDK for iOS and Amazon Cognito Identity sections of the iOS Developer Guide.

Application Delegate

The Transfer Utility for iOS uses the background transfer feature in iOS that allows data transfers to continue even when your app is not running. Call the following class method in your - application:handleEventsForBackgroundURLSession:completionHandler: application delegate so the OS can tell Transfer Utility when the transfer is complete when the app is not suspended.

Objective-C

- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler {
    /*
     Store the completion handler.
     */
    [AWSS3TransferUtility interceptApplication:application
           handleEventsForBackgroundURLSession:identifier
                             completionHandler:completionHandler];
}

Upload

Upload a File

Uploading a file is as simple as calling - uploadFile:bucket:key:contentType:expression:completionHander: on AWSS3TransferUtility:

Objective-C

NSURL *fileURL = // The file to upload.

AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility uploadFile:fileURL
                      bucket:@"YourBucketName"
                         key:@"YourObjectKeyName"
                 contentType:@"text/plain"
                  expression:nil
            completionHander:nil] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    }
    if (task.exception) {
        NSLog(@"Exception: %@", task.exception);
    }
    if (task.result) {
        AWSS3TransferUtilityUploadTask *uploadTask = task.result;
        // Do something with uploadTask.
    }

    return nil;
}];

If you want to know when the upload is complete, you can pass a completion handler block. Also, you can configure the upload behavior by passing AWSS3TransferUtilityUploadExpression. For example, you can add a upload progress feedback block to the expression object. Here is the code snippet with the completion handler and upload progress feedback:

Objective-C

NSURL *fileURL = // The file to upload.

AWSS3TransferUtilityUploadExpression *expression = [AWSS3TransferUtilityUploadExpression new];
expression.uploadProgress = ^(AWSS3TransferUtilityTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Update a progress bar.
    });
};

AWSS3TransferUtilityUploadCompletionHandlerBlock completionHandler = ^(AWSS3TransferUtilityUploadTask *task, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Alert a user for transfer completion.
        // On failed uploads, `error` contains the error object.
    });
};

AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility uploadFile:fileURL
                      bucket:@"YourBucketName"
                         key:@"YourObjectKeyName"
                 contentType:@"text/plain"
                  expression:expression
            completionHander:completionHandler] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    }
    if (task.exception) {
        NSLog(@"Exception: %@", task.exception);
    }
    if (task.result) {
        AWSS3TransferUtilityUploadTask *uploadTask = task.result;
        // Do something with uploadTask.
    }

    return nil;
}];

Upload Binary Data

You can upload an instance of NSData by calling - uploadData:bucket:key:contentType:expression:completionHander:

Objective-C

NSData *dataToUpload = // The data to upload.

AWSS3TransferUtilityUploadExpression *expression = [AWSS3TransferUtilityUploadExpression new];
expression.uploadProgress = ^(AWSS3TransferUtilityTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Update a progress bar.
    });
};

AWSS3TransferUtilityUploadCompletionHandlerBlock completionHandler = ^(AWSS3TransferUtilityUploadTask *task, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Alert a user for transfer completion.
        // On failed uploads, `error` contains the error object.
    });
};

AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility uploadData:dataToUpload
                      bucket:@"YourBucketName"
                         key:@"YourObjectKeyName"
                 contentType:@"text/plain"
                  expression:expression
            completionHander:completionHandler] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    }
    if (task.exception) {
        NSLog(@"Exception: %@", task.exception);
    }
    if (task.result) {
        AWSS3TransferUtilityUploadTask *uploadTask = task.result;
        // Do something with uploadTask.
    }

    return nil;
}];

This method saves the data as a file in a temporary directory. The next time AWSS3TransferUtility is initialized, the expired temporary files are cleaned up. If you upload many large objects to an Amazon S3 bucket in a short period of time, we recommend that you use the upload file method and manually purge the temporary files as soon as possible for added disk space efficiency.

Download

Here are the code snippets for downloads.

Download to a File

Objective-C

NSURL *fileURL = // The file URL of the download destination.

AWSS3TransferUtilityDownloadExpression *expression = [AWSS3TransferUtilityDownloadExpression new];
expression.downloadProgress = ^(AWSS3TransferUtilityTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Update a progress bar.
    });
};

AWSS3TransferUtilityDownloadCompletionHandlerBlock completionHandler = ^(AWSS3TransferUtilityDownloadTask *task, NSURL *location, NSData *data, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Alert a user for transfer completion.
        // On successful downloads, `location` contains the S3 object file URL.
        // On failed downloads, `error` contains the error object.
    });
};

AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility downloadToURL:fileURL
                         bucket:S3BucketName
                            key:S3DownloadKeyName
                     expression:expression
               completionHander:completionHandler] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    }
    if (task.exception) {
        NSLog(@"Exception: %@", task.exception);
    }
    if (task.result) {
        AWSS3TransferUtilityDownloadTask *downloadTask = task.result;
        // Do something with downloadTask.
    }

    return nil;
}];

Download as a Binary Data

Objective-C

AWSS3TransferUtilityDownloadExpression *expression = [AWSS3TransferUtilityDownloadExpression new];
expression.downloadProgress = ^(AWSS3TransferUtilityTask *task, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Update a progress bar.
    });
};

AWSS3TransferUtilityDownloadCompletionHandlerBlock completionHandler = ^(AWSS3TransferUtilityDownloadTask *task, NSURL *location, NSData *data, NSError *error) {
    dispatch_async(dispatch_get_main_queue(), ^{
        // Do something e.g. Alert a user for transfer completion.
        // On successful downloads, `data` contains the S3 object.
        // On failed downloads, `error` contains the error object.
    });
};

AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
[[transferUtility downloadDataFromBucket:S3BucketName
                                     key:S3DownloadKeyName
                              expression:expression
                        completionHander:completionHandler] continueWithBlock:^id(AWSTask *task) {
    if (task.error) {
        NSLog(@"Error: %@", task.error);
    }
    if (task.exception) {
        NSLog(@"Exception: %@", task.exception);
    }
    if (task.result) {
        AWSS3TransferUtilityDownloadTask *downloadTask = task.result;
        // Do something with downloadTask.
    }

    return nil;
}];

Background Transfer

All uploads and downloads continue in the background whether your app is active or in the background. If iOS terminates your app while transfers are ongoing, the system continues the transfers in the background then launches your app after the transfers finish. If the user terminates the app, any ongoing transfers stop.

You can’t persist blocks on disk so you need to rewire the completion handler and progress feedback blocks when your app relaunches. You should call - enumerateToAssignBlocksForUploadTask:downloadTask: on AWSS3TransferUtility to reassign the blocks as needed. Here is an example of reassigning blocks.

Objective-C

- (void)viewDidLoad {
    [super viewDidLoad];

    ...

    AWSS3TransferUtility *transferUtility = [AWSS3TransferUtility defaultS3TransferUtility];
    [transferUtility
     enumerateToAssignBlocksForUploadTask:^(AWSS3TransferUtilityUploadTask *uploadTask, __autoreleasing AWSS3TransferUtilityUploadProgressBlock *uploadProgressBlockReference, __autoreleasing AWSS3TransferUtilityUploadCompletionHandlerBlock *completionHandlerReference) {
         NSLog(@"%lu", (unsigned long)uploadTask.taskIdentifier);

         // Use `uploadTask.taskIdentifier` to determine what blocks to assign.

         *uploadProgressBlockReference = // Reassign your progress feedback block.
         *completionHandlerReference = // Reassign your completion handler.
     }
     downloadTask:^(AWSS3TransferUtilityDownloadTask *downloadTask, __autoreleasing AWSS3TransferUtilityDownloadProgressBlock *downloadProgressBlockReference, __autoreleasing AWSS3TransferUtilityDownloadCompletionHandlerBlock *completionHandlerReference) {
         NSLog(@"%lu", (unsigned long)downloadTask.taskIdentifier);

         // Use `downloadTask.taskIdentifier` to determine what blocks to assign.

         *downloadProgressBlockReference =  // Reassign your progress feedback block.
         *completionHandlerReference = // Reassign your completion handler.
     }];
}

You receive AWSS3TransferUtilityUploadTask and AWSS3TransferUtilityDownloadTask when you initiate the upload and download, respectively.

Objective-C

For upload:

if (task.result) {
    AWSS3TransferUtilityUploadTask *uploadTask = task.result;
    // Do something with uploadTask.
}

For download:

if (task.result) {
    AWSS3TransferUtilityDownloadTask *downloadTask = task.result;
    // Do something with downloadTask.
}

There is a property called taskIdentifier that uniquely identifies the transfer task object in the Transfer Utility. You may need to persist the identifier so that you can uniquely identify the upload/download task objects when rewiring the blocks for app relaunch.

Suspend, Resume, and Cancel

To suspend, resume, and cancel uploads and downloads, you need to retain references to AWSS3TransferUtilityUploadTask and AWSS3TransferUtilityDownloadTask. You can simply call - suspend, - resume, and - cancel on them.

Limitations

Behind the scenes, the Transfer Utility generates Amazon S3 pre-signed URLs and uses them to enable background transferring. Using Amazon Cognito Identity, you receive AWS temporary credentials that are valid for up to 60 minutes. It is not possible to generate S3 pre-signed URLs that last longer than 60 minutes. Due to this limitation, the Transfer Utility enforces 50-minute transfer timeouts (10-minute buffer for reducing AWS temporary credential regenerations). After 50 minutes, you receive a transfer failure.

We are exploring ways to overcome the technical limitations. Meanwhile, if you transfer a large amount of data that cannot be transferred within 50 minutes, use AWSS3TransferManager instead.

Talk to Us

We would like to hear from you! Ask questions or share feedback on GitHub issues or the AWS Developer Forum.

AWS Mobile SDK for iOS 2.2.0

by Yosuke Matsuda | on | | Comments

We have made a few significant changes in this version of the SDK. In this post, I am going to highlight those changes and show how you can update your code to incorporate them.

No More Third-Party Frameworks

The AWS Mobile SDK for iOS 2.2.0 no longer includes third-party frameworks. This change simplifies the SDK integration and avoids the duplicate symbols compiler error some of our developers have encountered. If your project contains the following frameworks from the previous version of the AWS Mobile SDK, you can remove them:

  • Bolts.framework
  • FMDB.framework
  • GZIP.framework
  • Mantle.framework
  • Reachability.framework
  • TMCache.framework
  • UICKeyChainStore.framework
  • XMLDictionary.framework

We prefixed these libraries with AWS and included them in AWSCore.framework. In most cases, you do not see these changes because these third-party libraries are not exposed to the developer. Bolts is the one exception.

You need to rename Bolts classes and change the prefix from BF to AWS. For example, the following code snippet

 AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
// Configure uploadRequest

[[transferManager upload:uploadRequest] continueWithBlock:^id(BFTask *task) {
    // Do something with the response
    return nil;
}];

must be rewritten to

 AWSS3TransferManager *transferManager = [AWSS3TransferManager defaultS3TransferManager];
AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
// Configure uploadRequest

[[transferManager upload:uploadRequest] continueWithBlock:^id(AWSTask *task) {
    // Do something with the response
    return nil;
}];

These classes must be updated:

  • BFTask -> AWSTask
  • BFExecutor -> AWSExecutor

If your app uses some of these third-party libraries, please grab a copy directly from each provider.

No More Service JSON Files

Starting with 2.2.0, you do not need to drag and drop service JSON files anymore. The previous versions of the SDK included the following JSON files:

  • autoscaling-2011-01-01.json
  • cognito-identity-2014-06-30.json
  • cognito-sync-2014-06-30.json
  • dynamodb-2012-08-10.json
  • ec2-2014-06-15.json
  • elasticloadbalancing-2012-06-01.json
  • email-2010-12-01.json
  • kinesis-2013-12-02.json
  • lambda-2015-03-31.json
  • machinelearning-2014-12-12.json
  • mobileanalytics-2014-06-30.json
  • monitoring-2010-08-01.json
  • s3-2006-03-01.json
  • sdb-2009-04-15.json
  • sns-2010-03-31.json
  • sqs-2012-11-05.json
  • sts-2011-06-15.json

These service definitions are now embedded in the frameworks; you do not have to import them manually. Please remove them if your project contains them. We believe these two changes considerably simplify the integration of the frameworks.

AWSMobileAnalytics Framework

Amazon Mobile Analytics client used to be a part of AWSCore. It did not have a dedicated framework like other AWS services. Starting with 2.2.0, we spun off AWSMobileAnalytics as an independent framework. The way you import AWSMobileAnalytics has been changed, so please update your project configuration accordingly.

Integrating AWSMobileAnalytics Framework

If you are using frameworks, you need to add AWSMobileAnalytics.framework to your project in addition to AWSCore.framework. Make sure you link libsqlite3.dylib and libz.dylib, and SystemConfiguration.framework. As a reminder, you no longer need the third-party frameworks and service definition JSON files. You can remove them if your project already has them.

If you use CocoaPods, you need to modify your Podfile:

 pod 'AWSCore'

to

 pod 'AWSMobileAnalytics'

to pick up the Amazon Mobile Analytics client.

Importing Frameworks

The import statement has been changed for AWSMobileAnalytics. You need to update

 #import <AWSCore/AWSCore.h>

to

 #import <AWSMobileAnalytics/AWSMobileAnalytics.h>

After you update the integration of the SDK, your code should compile and work as before.

Talk to Us

We would like to hear from you. Ask questions or share feedback on GitHub issues or the AWS Developer Forum.

The AWS Mobile SDK for iOS 2.1.x – Split Frameworks

by Yosuke Matsuda | on | | Comments

The previous version of the SDK included only two frameworks, AWSiOSSDKv2.framework and AWSCognitoSync.framework. For Amazon Cognito Sync, you import AWSCognitoSync.framework, and for all other AWS services, you import AWSiOSSDKv2.framework. These frameworks do not require the -ObjC linker flag, and we recommended not using that flag. If your app depends on third-party libraries that require the -ObjC flag, we recommend using -force_load instead to load the libraries in order to minimize the binary size impact on your app. However, some developers are already using the -ObjC flag in their production apps with many dependencies and do not want to change the Other Linker Flags to minimize the potential end-user impact of their app updates.

Split Frameworks

In order to minimize the app binary size impact on these developers and also to provide a clean, consistent methodology for importing, we have split the framework into the core and a framework per-service. Instead of AWSiOSSDKv2.framework and AWSCognitoSync.framework, the AWS Mobile SDK for iOS 2.1.1 includes the following frameworks:

Framework Dependencies
AWSCore.framework – contains the shared classes among all services and three service clients, Amazon Cognito Identity, Amazon Mobile Analytics, and Amazon STS Service models

  • cognito-identity-2014-06-30.json
  • mobileanalytics-2014-06-30.json
  • sts-2011-06-15.json

System libraries

  • libz.dylib
  • SystemConfiguration.framework

Third-party libraries

  • Bolts.framework (If your application uses the Facebook SDK, you may not need this framework, as it’s already included with the Facebook SDK.)
  • GZIP.framework
  • Mantle.framework
  • Reachability.framework
  • UICKeyChainStore.framework
  • XMLDictionary.framework
AWSAutoScaling.framework – contains an Auto Scaling client Service models

  • autoscaling-2011-01-01.json
AWSCloudWatch.framework – contains an Amazon CloudWatch client Service models

  • monitoring-2010-08-01.json
AWSDynamoDB.framework – contains an Amazon DynamoDB client Service models

  • dynamodb-2012-08-10.json
AWSEC2.framework – contains an Amazon EC2 client Service models

  • ec2-2014-06-15.json
AWSElasticLoadBalancing.framework – contains an Amazon Elastic Load Balancing client Service models

  • elasticloadbalancing-2012-06-01.json
AWSKinesis.framework – contains an Amazon Kinesis client Service models

  • kinesis-2013-12-02.json

System libraries

  • libsqlite3.dylib

Third-party libraries

  • FMDB.framework
  • TMCache.framework
AWSLambda.framework – contains an AWS Lambda client Service models

  • lambda-2015-03-31.json
AWSMachineLearning.framework – contains an Amazon Machine Learning client Service models

  • machinelearning-2014-12-12.json
AWSS3.framework – contains an Amazon S3 client Service models

  • s3-2006-03-01.json

Third-party libraries

  • TMCache.framework
AWSSES.framework – contains an Amazon SES client Service models

  • email-2010-12-01.json
AWSSimpleDB.framework – contains an Amazon SimpleDB client Service models

  • sdb-2009-04-15.json
AWSSNS.framework – contains an Amazon SNS client Service models

  • sns-2010-03-31.json
AWSSQS.framework – contains an Amazon SQS client Service models

  • sqs-2012-11-05.json
AWSCognito.framework – contains an Amazon Cognito Sync client Service models

  • cognito-sync-2014-06-30.json

System libraries

  • libsqlite3.dylib

Integrating the Frameworks

Note that you always need to import AWSCore.framework and its dependencies because it is shared among all services. If you want to use AWS services not included in the core, you need to include the framework for the service and its dependencies. For example, if you want to use Amazon Mobile Analytics, you need to import the following components into your Xcode project:

Framework Dependencies
AWSCore.framework Service models

  • cognito-identity-2014-06-30.json
  • mobileanalytics-2014-06-30.json
  • sts-2011-06-15.json

System libraries

  • libz.dylib
  • SystemConfiguration.framework

Third-party libraries

  • Bolts.framework
  • GZIP.framework
  • Mantle.framework
  • Reachability.framework
  • UICKeyChainStore.framework
  • XMLDictionary.framework

If you want to use Amazon Kinesis, you need to import:

Framework Dependencies
AWSCore.framework Service models

  • cognito-identity-2014-06-30.json
  • mobileanalytics-2014-06-30.json
  • sts-2011-06-15.json

System libraries

  • libz.dylib
  • SystemConfiguration.framework

Third-party libraries

  • Bolts.framework
  • GZIP.framework
  • Mantle.framework
  • Reachability.framework
  • UICKeyChainStore.framework
  • XMLDictionary.framework
AWSKinesis.framework Service models

  • kinesis-2013-12-02.json

System libraries

  • libsqlite3.dylib

Third-party libraries

  • FMDB.framework
  • TMCache.framework

Make sure to remove AWSiOSSDKv2.framework and AWSCognitoSync.framework from the previous version of the SDK when upgrading, or you may receive the duplicate symbol compiler error.

Integrating with CocoaPods

In order to align with the framework, we split our pods to the core and per-service pods:

pod 'AWSCore'
pod 'AWSAutoScaling'
pod 'AWSCloudWatch'
pod 'AWSDynamoDB'
pod 'AWSEC2'
pod 'AWSElasticLoadBalancing'
pod 'AWSKinesis'
pod 'AWSLambda'
pod 'AWSMachineLearning'
pod 'AWSS3'
pod 'AWSSES'
pod 'AWSSimpleDB'
pod 'AWSSNS'
pod 'AWSSQS'
pod 'AWSCognito'

If you want to use Amazon Mobile Analytics, you need to add:

pod 'AWSCore'

to your Podfile. If you want to use Amazon Kinesis, you need to add:

pod 'AWSKinesis'

You do not need to import AWSCore separately in order to use Amazon Kinesis because CocoaPods resolves the dependencies for you and imports AWSCore for you. The only exception to this rule is Amazon Cognito Sync. When using Amazon Cognito Sync, you need to add both AWSCore and AWSCognito to your Podfile:

pod 'AWSCore'
pod 'AWSCognito'

Make sure to remove AWSiOSSDKv2 and AWSCognitoSync from the previous version to minimize the app binary size.

Once you update your Podfile, you just need to call:

$ pod install

to import the new SDK.

Importing the SDK

The way you import the SDK into your file has been updated. With the previous version, you import the SDK as follows:

CocoaPods

#import "AWSCore.h"
#import "S3.h"
#import "DynamoDB.h"
#import "SQS.h"
#import "SNS.h"

Frameworks

#import <AWSiOSSDKv2/AWSCore.h>
#import <AWSiOSSDKv2/S3.h>
#import <AWSiOSSDKv2/DynamoDB.h>
#import <AWSiOSSDKv2/SQS.h>
#import <AWSiOSSDKv2/SNS.h>

With 2.1.x, you can import the SDK with #import <AWSServiceName/AWSServiceName.h> whether you use CocoaPods or frameworks:

#import <AWSCore/AWSCore.h>
#import <AWSS3/AWSS3.h>
#import <AWSDynamoDB/AWSDynamoDB.h>
#import <AWSSQS/AWSSQS.h>
#import <AWSSNS/AWSSNS.h>

We hope these changes allow our developers to reduce their app binary sizes and provide cleaner and more consistent APIs. For more details on how to import each component, see Set Up the SDK for iOS. If you encounter issues with the SDK, please let us know at GitHub issues or Mobile Development Discussion Forum.