Saturday, January 2, 2016

Android Application - Load Images from App Data Directory and Display in Gallery

Hello,

Recently in one of my project, we have list of images in one of the application directory. The requirement was to read those images and display like a gallery. In this blog I am going to explain how to do this.

First of all add following file in your layout xmls and name it activity_image_list.xml. Following is the code.

<?xml version="1.0" encoding="utf-8"?>
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
     android:id="@+id/imageGridview"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:numColumns="auto_fit"
    android:columnWidth="120dp"
    android:horizontalSpacing="10dp"
    android:verticalSpacing="10dp"
    android:gravity="center"
    android:stretchMode="columnWidth"  >

</GridView>

This is the Grid View which will show the images like a gallery. Now add an activity and set this xml as contentView in onCreate method.

super.onCreate(savedInstanceState);
setContentView(R.layout.activity_image_list);


Now for grid we need to have adapter so I created following class and add it to activity.

public class ImageAdapter extends BaseAdapter{
        private Context mContext;
        public int getCount() {
             return mThumbIds.length;
        }                               
        public Object getItem(int position) {
             return mThumbIds[position];
        }                               
        public long getItemId(int position) {
             return 0;
        }                               
        public ImageAdapter(Context c) {
             mContext = c;
        }    
        
        public void setFiles(File[] savedSnapshots){
        this.mThumbIds = savedSnapshots;
        }
                              
        public View getView(int position, View convertView, ViewGroup parent) {
             ImageView imageView;
             if (convertView == null){  
                imageView = new ImageView(mContext);
                imageView.setLayoutParams(new GridView.LayoutParams(85, 85));
                imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
                imageView.setPadding(8, 8, 8, 8);
             } 
             else{
                 imageView = (ImageView) convertView;
             }
             try{
             Bitmap thumbnail = BitmapFactory.decodeFile(mThumbIds[position].getAbsolutePath());
                 imageView.setImageBitmap(thumbnail);
             }catch(Exception e){
             
             }
             return imageView;
        }
                             
        private File[] mThumbIds = {};        
    }

Now we will load list of images from specific directory and display it in grid,

GridView gridview = (GridView) findViewById(R.id.imageGridview);
ImageAdapter adapter = new ImageAdapter(this);
ContextWrapper cw = new ContextWrapper(getApplicationContext());
File directory = cw.getDir("snapshots", Context.MODE_PRIVATE);
snapshots = directory.listFiles();
adapter.setFiles(snapshots);
gridview.setAdapter(adapter);

As you can see above we are reading images from snapshots directory and create an adapter and set list of files in it. 

And inside getView method of adapter we are creating bitmap and assigned it to image view. This way images will be displayed in grids..

Hope this helps you.

Resolve App Transport Security Exceptions in iOS 9 and OSX 10.11

Hello,

Recently I was working on an old iOS application for my client. This app was developed on iOS 7 and we were adding few updates, I was using iOS 9 SDK on my Xcode. While development I found that none of the web services were working on app. In short app was not able to get data from remote URLs. I show the logs and there was App Transport Security Exception.

Let's first understand what is App Transport Security (ATS).

At WWDC 2015, Apple announced “App Transport Security” for iOS 9 and OSX 10.11 El Capitan. The “What’s New in iOS” guide for iOS 9 explains:

App Transport Security (ATS) lets an app add a declaration to its Info.plist file that specifies the domains with which it needs secure communication. ATS prevents accidental disclosure, provides secure default behavior, and is easy to adopt. You should adopt ATS as soon as possible, regardless of whether you’re creating a new app or updating an existing one.

If you’re developing a new app, you should use HTTPS exclusively. If you have an existing app, you should use HTTPS as much as you can right now, and create a plan for migrating the rest of your app as soon as possible.

In simple terms, this means that if your application attempts to connect to any HTTP server (in this example, yourserver.com) that doesn’t support the latest SSL technology (TLSv1.2), your connections will fail with an error like this:

CFNetwork SSLHandshake failed (-9801)
Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo=0x7fb080442170 {NSURLErrorFailingURLPeerTrustErrorKey=, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorCodeKey=-9802, NSUnderlyingError=0x7fb08055bc00 "The operation couldn’t be completed. (kCFErrorDomainCFNetwork error -1200.)", NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://yourserver.com, NSErrorFailingURLStringKey=https://yourserver.com, _kCFStreamErrorDomainKey=3}

In short app should have all the remote calls with Https protocol. How ever in my case it was not possible as my client refused to install SSL certificate. So I have to bypass App Transport Security.

So here how to do this. Open your project in Xcode and open info.plist file and add following key.

App Transport Security Settings



Now add one more key under that key which you added above. Following is the name of key.

Allow Arbitrary Loads and set it's value to YES. After adding both keys your info.plist should look as below.



That's it and now all your services should work with http protocols.



Send Apple Push Notifications (APN) from PHP Web Application

Hello,

In this blog I am going to explain how to configure your PHP server to send Apple Push Notifications (APN). Please note you will need a valid apple developer account for this.

First of all you will need a PEM file on your server. Following are the steps to create PEM file. Log into apple member center with your developer account credentials.

https://developer.apple.com/membercenter/index.action

Go to Certificates, Identifies & Profiles

Select iOS Apps - > Certificates

We will see how to create both development and production PEM file. Click on + sign on top right corner to add new certificate. It will show you list of certificate types.



Choose from development if you want development certificate or choose from production if you want production certificate. Click on Next and it will ask you to select your application in next step.



Select your desired application and click on next. Now you have to upload certificate signing request. Following are steps to generate certificate signing request


  • Open Keychain Access on your Mac (located in Applications/Utilities).
  • Open Preferences and click Certificates. Make sure both Online Certificate Status Protocol and Certificate Revocation List are set to Off.
  • Choose Keychain Access > Certificate Assistant > Request a Certificate From a Certificate Authority.
  • Note: If you have a private key selected when you do this, the CSR won’t be accepted. Make sure no private key is selected. Enter your user email address and common name. Use the same address and name as you used to register in the iOS Developer Program. No CA Email Address is required.
  • Select the options “Saved to disk” and “Let me specify key pair information” and click Continue.
  • Specify a filename and click Save.

Upload CSR in the following screen and click on continue.



In the next step click on generate and it will generate your certificate. Download certificate to your local machine and double click on it and it will be added to key chain access and it will open and should show you following screen.



As you can see above development certificates are added as Apple Development iOS Push Services and Production certificate are added as Apple Push Services. Now click on left arrow and expand it. You will see name of certificate signing authority there. Select both name and certificate and double tap on it it will show you following menu.



Click on export two items and save .p12 file.



Now we will convert .p12 file to .pem file using OpenSSL. Open your terminal and run following command.

openssl pkcs12 -in Certificates.p12 -out Certificates.pem -nodes -clcerts

That's it your pem file is ready. Upload it your server and add following functions to send APNs for production and development respectively in your PHP.

public function sendAPNProduction($deviceToken, $msg, $message){

        $payload['aps'] = array('alert' => $msg, 'badge' => 1, 'sound' => 'default');
        $payload['messages'] = $message;
        $payload = json_encode($payload);

        $apnsCert = 'Certicates.pem';

        $streamContext = stream_context_create();
        stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

        $apns = stream_socket_client('ssl://gateway.push.apple.com:2195', $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);

        $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
        fwrite($apns, $apnsMessage);

        //socket_close($apns); seems to be wrong here ...
        fclose($apns);

}

public function sendAPNDevelopment($deviceToken, $msg, $message){

        $payload['aps'] = array('alert' => $msg, 'badge' => 1, 'sound' => 'default');
        $payload['messages'] = $message;
        $payload = json_encode($payload);

        $apnsCert = 'Certicates.pem';

        $streamContext = stream_context_create();
        stream_context_set_option($streamContext, 'ssl', 'local_cert', $apnsCert);

        $apns = stream_socket_client('ssl://gateway.sandbox.push.apple.com:2195', $error, $errorString, 2, STREAM_CLIENT_CONNECT, $streamContext);

        $apnsMessage = chr(0) . chr(0) . chr(32) . pack('H*', str_replace(' ', '', $deviceToken)) . chr(0) . chr(strlen($payload)) . $payload;
        fwrite($apns, $apnsMessage);

        //socket_close($apns); seems to be wrong here ...
        fclose($apns);

}

That's it and now your PHP web app is ready to send Apple Push Notifications (APNs). I hope this helps you.