Tuesday, 22 May 2018

How to upload files to S3 from iOS app written in Objective C using AWS Cognito identity pool

Background

This post assumes you have setup Cognito identity pool as explained in the previous post -
If not, then please refer the previous post and set that up. Before starting with using this you should have -
  1. Identity pool ID
  2. AWS region where pool and S3 bucket reside
  3. S3 bucket name
We will use above in configuration and implementation that follows.

How to upload files to S3 from iOS app written in Objective C using AWS Cognito identity pool

  • First, go to your pod file and update following dependencies -

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'


target 'TestApp' do
  # Uncomment the next line if you're using Swift or would like to use dynamic frameworks
  # use_frameworks!
  # Pods for TestApp


pod 'AWSMobileClient', '~> 2.6.18'  # For AWSMobileClient
pod 'AWSS3', '~> 2.6.18'            # For file transfers
pod 'AWSCognito', '~> 2.6.18'       # For data sync

end

  • Next run "Run pod install --repo-update" from the command line
  • Once you have the dependencies installed we can now write Objective C code to upload a file to S3.


//
//  FileUploader.m
//  TestApp
//
//  Created by Aniket on 22/05/18.
//


#import <Foundation/Foundation.h>


#import "FileUploader.h"
#import <AWSS3/AWSS3.h>
#import <AWSCore/AWSCore.h>




@implementation FileUploader


static AWSS3TransferManager *transferManager;


+ (void) initialize {
    
    if (self == [FileUploader class]) {
        AWSCognitoCredentialsProvider *credentialsProvider = [[AWSCognitoCredentialsProvider alloc] initWithRegionType:AWSRegionUSEast1 identityPoolId:@"us-east-1:f847843f-0162-43c2-b73f-efdc7c69cce2"];
        AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider];
        [AWSS3TransferManager registerS3TransferManagerWithConfiguration:[[AWSServiceConfiguration alloc] initWithRegion:AWSRegionUSEast1 credentialsProvider:credentialsProvider] forKey:s3TransferManagerKey];


        AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
                                        
        transferManager = [AWSS3TransferManager S3TransferManagerForKey:s3TransferManagerKey];
    }
    
}


+ (void)uploadFile
{
    
    
    NSURL *uploadingFileURL = [NSURL fileURLWithPath: @"PATH_TO_FILE";
    AWSS3TransferManagerUploadRequest *uploadRequest = [AWSS3TransferManagerUploadRequest new];
    
    
    uploadRequest.bucket = s3Bucket;
    int timestamp = [[NSDate date] timeIntervalSince1970];
    uploadRequest.key = [NSString stringWithFormat:@"%@-%d%@",@"testfile",timestamp,@".txt"];
    uploadRequest.body = uploadingFileURL;
    
    [[transferManager upload:uploadRequest] continueWithExecutor:[AWSExecutor mainThreadExecutor]
                                                       withBlock:^id(AWSTask *task) {
                                                           if (task.error) {
                                                               if ([task.error.domain isEqualToString:AWSS3TransferManagerErrorDomain]) {
                                                                   switch (task.error.code) {
                                                                       case AWSS3TransferManagerErrorCancelled:
                                                                       case AWSS3TransferManagerErrorPaused:
                                                                           break;
                                                                           
                                                                       default:
                                                                           NSLog(@"Error uploading file to S3: %@", task.error);
                                                                           break;
                                                                   }
                                                               } else {
                                                                   // Unknown error.
                                                                   NSLog(@"Error uploading file to S3: %@", task.error);
                                                               }
                                                           }
                                                           
                                                           if (task.result) {
                                                               AWSS3TransferManagerUploadOutput *uploadOutput = task.result;
                                                               // The file uploaded successfully.
                                                               NSLog(@"uploading file to S3 was successful: %@", uploadOutput);
                                                           }
                                                           return nil;
                                                       }];
    
}
@end


In above code replace the identity pool id and region as per your configuration settings. This is Objective C code, if you want to see Swift or Android - Java please refer https://docs.aws.amazon.com/aws-mobile/latest/developerguide/how-to-integrate-an-existing-bucket.html


Related Links

How to setup Cognito Identity Pool for unauthenticated or authenticated access to AWS resources like S3

Background

Many time when you are creating application be it mobile or web you have to provide an authentication mechanism for users to sign in before they can use your apps or websites features. AWS Cognito service does the same thing. 
  • Amazon Cognito makes it easy for you to have users sign up and sign in to your apps, federate identities from social identity providers, secure access to AWS resources and synchronize data across multiple devices, platforms, and applications.
You can do 3 things using this service -
  1. With Cognito Your User Pools, you can easily and securely add sign-up and sign-in functionality to your mobile and web apps with a fully-managed service that scales to support hundreds of millions of users.
  2. With Cognito Federated Identities, your users can sign-in through social identity providers such as Facebook and Twitter, or through your own identity solution, and you can control access to AWS resources from your app.        
  3. With Cognito Sync, your app can save user data, such as preferences and game state, and sync that data to make your users' experiences consistent across their devices and when they are disconnected.             
NOTE: AWS Cognito is a region-specific service so you have to select a region and make sure this service is available in that region. For this post, I am going to use us-east-1(N.Virginia).

Also in this post, I am going to show how we can create a federated identity pool which can be used to authenticate and access AWS resources. Though I am going to limit this post to setting-up the identity pool and corresponding AWS changes we will see how we can use this to upload sample files to Amazon S3 bucket.


How to setup Cognito Identity Pool for unauthenticated or authenticated access to AWS resources

  • Sign into AWS console and go to Cognito service.


  • Now click on "Manage Federated Identities"
  • Provide a name for your identity pool. Eg. athakur_test
  • If you want unauthenticated users to use this pool for authenticating and accessing AWS resources select "". I am going to select this since finally, I want to use this pool to upload files to S3. 

NOTE: Amazon Cognito can support unauthenticated identities by providing a unique identifier and AWS credentials for users who do not authenticate with an identity provider. If your application allows customers to use the application without logging in, you can enable access to unauthenticated identities.

  • If you want to provide access to authenticated users only then use one of the Authentication providers like Facebook, Amazon, Google etc
  • Click on "create pool".

  • Next screen you should see the roles that AWS will create for you. You can select "View details" to see the role details. 
  • Finally, click "Allow"
NOTE1: Assigning a role to your application end users helps you restrict access to your AWS resources. Amazon Cognito integrates with Identity and Access Management (IAM) and lets you select specific roles for both your authenticated and unauthenticated identities. 

NOTE2: By default, Amazon Cognito creates a new role with limited permissions - end users only have access to Cognito Sync and Mobile Analytics. You can modify the roles if your application needs access to other AWS resources, such as S3 or DynamoDB.

You can see click on video details to see this default policy document -

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "mobileanalytics:PutEvents",
        "cognito-sync:*"
      ],
      "Resource": [
        "*"
      ]
    }
  ]

}


We will see how to attach additional permissions to this role later.



As you can see 2 roles are created - one for the authenticated user and other for the unauthenticated user -
  1. Cognito_athakur_testAuth_Role
  2. Cognito_athakur_testUnauth_Role
On the next page, you should see some sample code - one for getting credentials and other for Cognito sync -


Get AWS credentials :

// Initialize the Amazon Cognito credentials provider
CognitoCachingCredentialsProvider credentialsProvider = new CognitoCachingCredentialsProvider(
    getApplicationContext(),
    "us-east-1:f847843f-0162-43c2-b73f-efdc7c69cce2", // Identity pool ID
    Regions.US_EAST_1 // Region
);


Store User Data:

// Initialize the Cognito Sync client
CognitoSyncManager syncClient = new CognitoSyncManager(
   getApplicationContext(),
   Regions.US_EAST_1, // Region
   credentialsProvider);

// Create a record in a dataset and synchronize with the server
Dataset dataset = syncClient.openOrCreateDataset("myDataset");
dataset.put("myKey", "myValue");
dataset.synchronize(new DefaultSyncCallback() {
    @Override
    public void onSuccess(Dataset dataset, List newRecords) {
  //Your handler code here
    }
});


  • Note down the Identity pool id and region . In my case identity pool id is "us-east-1:f847843f-0162-43c2-b73f-efdc7c69cce2" and region is us-east-1. We will need it in subsequent setup.
The last part that is remaining now is to add additional permissions to our new role so that Cognito pool users can access other required AWS services - in this case since we need to upload files to S3 we just need S3 put access.

NOTE: Make sure Cognito identity pool should be created in same region as S3 bucket.

So go to IAM and go to roles and select it. Now click add inline policy and add following JSON policy -

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Stmt1526901559336",
            "Action": [
                "s3:PutObject"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::<BUCKET_NAME>/*"
        }
    ]
}


You have to replace <BUCKET_NAME> with your actual S3 bucket name. Always make IAM policies as stricter as possible. In this case, we are just giving put object permission on the desired S3 bucket only.

NOTE: This was for upload to S3 bucket but you can provide access to other services that you desire. If you need to create the policy you can use policy generator AWS provides - https://awspolicygen.s3.amazonaws.com/policygen.html


At this point, your Cognito service is all set up for implementation. In the next post, we will see how we can use this to implement it in our mobile or web application.

Related Links

Saturday, 19 May 2018

How to get the current time in milliseconds

Background

In many scenarios, we need the current time in milliseconds. In this post, we will see various methods to get the time in milliseconds since the UNIX epoch (January 1, 1970 00:00:00 UTC) in various programming languages.

How to get the current time in milliseconds

Following are ways you can get  current time in milliseconds for various programming languages -

  • ActionScript    
    • (new Date()).time
  • C++ 
    • std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count()
  • C#.NET  
    • DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()
  • Clojure 
    • (System/currentTimeMillis)
  • Excel / Google Sheets*  
    • = (NOW() - CELL_WITH_TIMEZONE_OFFSET_IN_HOURS/24 - DATE(1970,1,1)) * 86400000
  • Go / Golang 
    • time.Now().UnixNano() / 1000000
  • Hive*   
    • unix_timestamp() * 1000
  • Java / Groovy / Kotlin  
    • System.currentTimeMillis()
  • Javascript  
    • new Date().getTime()
  • MySQL*  
    • UNIX_TIMESTAMP() * 1000
  • Objective-C 
    • (long long)([[NSDate date] timeIntervalSince1970] * 1000.0)
  • OCaml   
    • (1000.0 *. Unix.gettimeofday ())
  • Oracle PL/SQL* 
    •  SELECT (SYSDATE - TO_DATE('01-01-1970 00:00:00', 'DD-MM-YYYY HH24:MI:SS')) * 24 * 60 * 60 * 1000 FROM DUAL
  • Perl    
    • use Time::HiRes qw(gettimeofday); print gettimeofday;
  • PHP 
    • round(microtime(true) * 1000)
  • PostgreSQL  
    • extract(epoch FROM now()) * 1000Python  int(round(time.time() * 1000))
  • Qt  
    • QDateTime::currentMSecsSinceEpoch()
  • R*  
    • as.numeric(Sys.time()) * 1000
  • Ruby    
    • (Time.now.to_f * 1000).floor
  • Scala   
    • val timestamp: Long = System.currentTimeMillis
  • SQL Server  
    • DATEDIFF(ms, '1970-01-01 00:00:00', GETUTCDATE())
  • SQLite* 
    • STRFTIME('%s', 'now') * 1000
  • Swift*  
    • let currentTime = NSDate().timeIntervalSince1970 * 1000
  • VBScript / ASP  
    • offsetInMillis = 60000 * GetTimeZoneOffset()
  • WScript.Echo 
    • DateDiff("s", "01/01/1970 00:00:00", Now()) * 1000 - offsetInMillis + Timer * 1000 mod 1000



I recently investigated this as I wanted MicrosoftDateFormat in objective C. We can do this as follows -

  • NSString *date = [NSString stringWithFormat:@"/Date(%lld)/",(long long)([currentTag.firstSeenTime timeIntervalSince1970] * 1000.0)];


NOTE: timeIntervalSince1970 gives you the number of seconds whereas Newtonsoft.Json library (C#) gives it in milliseconds so you need multiple by 1000.0 to get milliseconds.


Related Links



Friday, 11 May 2018

How to enable touch to click on your Mac

Background

If you are a Mac user then you must be familiar with the peculiar trackpad gestures and usage Mac offers. Personally, I feel touch to click is a much better option then physically pressing the trackpad. In this post, I will show you how to do the same. I am using MacBook Pro running Sierra (10.13.4).

How to enable touch to click on your Mac

  • Go to "Preferences" and select "Trackpad"
  • Under "Point and Click" select "Tap to Click"




  • Notice how "Click with two fingers" is also changed to "Click or tab with two finders" for secondary click.
  • You can use this checkbox to enable or disable "Tap to click"

How to enable touch to click on your Mac with command line

You can do the same above setting with the command line. Execute following commands in your Terminal.

  • sudo defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool true
  • sudo defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 1
  • sudo defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 1

NOTE: You will need to reboot your system for changes to take effect.

Similarly, to disable you can do

  • sudo defaults write com.apple.driver.AppleBluetoothMultitouch.trackpad Clicking -bool false
  • sudo defaults -currentHost write NSGlobalDomain com.apple.mouse.tapBehavior -int 0
  • sudo defaults write NSGlobalDomain com.apple.mouse.tapBehavior -int 0
Again reboot your machine to take effect.



Related Links




Sunday, 29 April 2018

Objective C programming in Windows with GNUStep

Background

Objective C is the programming language that is used for iOS development. To learn iOS development you need a Mac since you need Xcode to develop it. However, there is no such limitation for learning Objective C. So in this post I am going to show you how to compile and run Objective C programs on windows.


Installing GNUstep on Windows

GNUstep is a free development environment that is based on MinGW and MSYS. It has set of tools and compilers (including GCC) that lets you compile objective c programs on windows. To completely install GNUstep you need to install 3 setup files -

  1. GNUstep MSYS System
  2. GNUstep Core
  3. GNUstep Devel
 You can download and install the same from http://www.gnustep.org/windows/installer.html.

Installation : For the full environment for compiling and running GNUstep. Install the following packages in order. First install the gnustep-msys-system package, which contains all the packages required to run GNUstep (shell, graphics libraries, etc). Then install gnustep-core, which contains the core GNUstep libraries. If you want to compile and develop your own GNUstep applications, also install the gnustep-devel package.

The default installation of GNUstep would go to
  • C:\GNUstep

You can also use ProjectCenter which is a GUI extension of GNUStep.

Hello World - Objective C

Now create a new file called helloworld.m and add following content to it -

#import <Foundation/Foundation.h>

int main (int argc, const char * argv[])
{
   NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
   NSLog (@"Hello World!");

   [pool drain];
   return 0;
}

I have saved it at location -
  • C:\GNUstep\home\<username>\Development\helloworld.m

Once you have saved it open the GNUstep shell. For me, it is at the following location -
  • C:\Users\<username>\AppData\Roaming\Microsoft\Windows\Start Menu\Programs\GNUstep
Once you have opened it navigate to the directory you have helloworld.m file. Then run following command -

 gcc -o helloworld helloworld.m -I /GNUstep/System/Library/Headers -L /GNUstep/System/Library/Libraries -lobjc -lgnustep-base -fconstant-string-class=NSConstantString


This should create a helloworld.exe file in the same directory. Now run ./helloworld.exe and it should print "Hello World!". This is captured in the screenshot below -







Related Links

t> UA-39527780-1 back to top