Easier Webhook Testing with Ngrok

Picture this scenario :

You have built a web app that has webhooks from other service. But everytime you want to test it out, you have to deploy your app, and keep a look out on your logs as the request trickles in. 

or

You are working with a mobile developer in-house, and you both want to test an API. You deploy the app, even if it is a minute change and then wait to see if all works properly. 

I am sure, as a developer, we have all been there. Deploying apps for a couple of small changes, and make it run through your entire CI/CD cycle can be exhausting. And so I was delighted, when I stumbled upon ngrok.

ngrok is a tool that allows you to access your localhost via Internet. This can save you from countless hours of frustrations by avoiding deploying code for minor changes.

Running ngrok is as simple as downloading the relevant files from the website. Once downloaded, on Mac / Linux – type

Once you have unzipped the contents, ensure your localhost is running and you know the port number. To get your server accessible via Internet, type

This would start ngrok, and now your web app is publicly accessible via the Internet. The terminal also shows the incoming request to your app

The Tunnel URL in my case is http://b3991383.ngrok.io, which points to port 8000 on my device. You can now update the tunnel URL in your webhooks, or pass it on to your client to test the app.

One cool feature of ngrok is it’s live dashboard – which allows you to inspect the status of server as well as the requests that are coming in. You can access this dashboard by navigating to http://localhost:4040/inspect/http

 

 

Apart from using ngrok for development, you can also use it to host your own webmail or other apps. ngrok also offers a paid tier with support for custom domains and other features.

ngrok has been easily one of the tools that has saved me hours of development time, and the paid plan is just worth it.

How to create a Diawi link ?

Overview

Diawi is tool for iOS and Android developers to upload and install applications to their devices. Developer can upload an .ipa file for iOS or the .apk file for Android on the website and then provide the link to the testers or users. The testers/users can open the link in their browser and install the app.

Why should i use Diawi?

  • Easy to use.
  • Faster uploading the app and providing links to the testers.

Prerequisite

Registering an App ID :-

  • Sign in to developer.apple.com/account, and click Certificates, IDs & Profiles.
  • Under Identifiers, select App IDs.
  • Click the Add button (+) in the upper-right corner.
  • Enter a name or description for the App ID in the Description field.
  • Create an explicit App ID and enter the app’s bundle ID in the Bundle ID field.
  • Select the corresponding checkboxes to enable the app services you want to use.
  • Click Continue, Review the registering information and click Done.

Registering a Device:-

To register a device using your developer account, you need to have the device name and device ID.
  • In to developer.apple.com/account, and click Certificates, IDs & Profiles.
  • Under Devices, select All.
  • Click the Add button (+) in the upper-right corner.
  • Select Register Device.
  • Enter a device name and the device ID (UDID).
  • Click Register.

Create a Provisioning Profile :-

  • In to developer.apple.com/account, and click Certificates, IDs & Profiles.
  • Under Provisioning Profiles, select All.
  • Click the Add button (+) in the upper-right corner.
  • Choose the Development method, and click Continue.
  • Choose the App ID you used for development (the App ID that matches your bundle ID) from the App ID pop-up menu, and click Continue.
  • Select the certificates, and click Continue.
  • Select the devices you wish to include in this provisioning profile
  • Enter a profile name, and click Continue.
  • Click Done.

Create .ipa file.

  • Open the Xcode, choose a Generic iOS Device.
  • Under the Project section click Archive.
  • Select the Archive, click Export and then choose Save for AdHoc Deployment.
  • Select the development team, and save .ipa file.

Upload to Diawi

  • Go to https://www.diawi.com.
  • Drag and drop the .ipa file of your app.
  • Click Send after the file is uploaded.
  • Copy the Diawi link and send it to testers/users for installation.

Create your own Custom Input View

While working on a client project, we had to build a custom input view which allowed users to respond back soon.

UIKit allows apps to customize input views for the system keyboard, it will allow customizing the selection for the input view

After figuring out input views, I found it is easy to create your own custom input view

Let’s get started how to build a sample app to use custom input view

Final_Sample

This is how it will look after building

Creating a custom input view

Let’s create a Custom Input view named Keyboard To get started, Create a new Xcode project or open an existing project. Select File\New\File choose View in User Interface Section name the File as Keyboard, it will create a new file as Keyboard.xib

Here we can use any UI element, we have to display list of message template, we will use collection view for that

  • Drag a Collection View to view give 4 constraint to its margin
  • Make a class for keyboard xib, File\New\File in iOS section choose Cocoa Touch and subclass as UIView name it as Keyboard.swift
  • Set the nibs file owner as Keyboard.swift, please take a note that we have to set File owner as our custom class Keyboard.swift not, and make sure that the custom class for the root view is blank

file_owner

  • Make a new collection view cell
  • In xib add a textview, set its editable false and add 4 constraint to view and take a reference of it in Keyboard.swift

now put the following code in Keyboard.swift

import UIKit
protocol KeyboardDelegate: class {
    //Called when keyboard button tapped
    func keyWasTapped(character: String)
}

protocol KeyboardDataSource: class {
    //Data array for keyboard
    func dataForKeyboard()-> [String]
}

class Keyboard: UIView {
    @IBOutlet var dataCollectionView: UICollectionView!
    static let collectionViewIdentifier = "DataSelectionCell"
    fileprivate let sectionInsets = UIEdgeInsets(top: 10.0, left: 10.0, bottom: 10.0, right: 10.0)
    // This variable will be set as the view controller so that
    // the keyboard can send messages to the view controller.
    weak var delegate: KeyboardDelegate?
    // This variable will ask for data to the view controller.
    weak var dataSource: KeyboardDataSource?

    // MARK:- keyboard initialization
    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        initializeSubviews()
    }

    override init(frame: CGRect) {
        super.init(frame: frame)
        initializeSubviews()
    }
    // 1
    func initializeSubviews() {
        let xibFileName = "Keyboard" // xib extention not included
        let view = Bundle.main.loadNibNamed(xibFileName, owner: self, options: nil)?[0] as! UIView
        self.addSubview(view)
        view.frame = self.bounds
        //Register collection view cell
        let cellNib = UINib(nibName: Keyboard.collectionViewIdentifier, bundle: nil)
        dataCollectionView.register(cellNib, forCellWithReuseIdentifier: Keyboard.collectionViewIdentifier)
        dataCollectionView.delegate = self
        dataCollectionView.dataSource = self
    }
    // 2
    func viewTapped(gestureReconizer: UITapGestureRecognizer) {
        let point = gestureReconizer.location(in: dataCollectionView)
        let indexPath = dataCollectionView.indexPathForItem(at: point)
        // Trigger delegate for tap action
        dataCollectionView.delegate?.collectionView!(dataCollectionView, didSelectItemAt: indexPath!)
    }

}
// MARK:- UICollectionViewDelegate
extension Keyboard: UICollectionViewDelegate {
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        // delegate (ie, the view controller)
        let dataArray = dataSource?.dataForKeyboard()
        let message = dataArray?[indexPath.row]
        self.delegate?.keyWasTapped(character: message!) // Inform delegate
    }
}
// MARK:- UICollectionViewDataSource
extension Keyboard: UICollectionViewDataSource {
    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        if let dataArray = self.dataSource?.dataForKeyboard(){
            return dataArray.count
        }
        return 0
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = dataCollectionView.dequeueReusableCell(withReuseIdentifier: Keyboard.collectionViewIdentifier, for: indexPath) as! DataSelectionCell
        let dataArray = dataSource?.dataForKeyboard()
        // Add tap gesture to TextView to send tap event, as TextView will cover entire cell
        let tap = UITapGestureRecognizer(target: self, action: #selector(viewTapped(gestureReconizer:)))
        cell.dataTextView.addGestureRecognizer(tap)
        cell.dataTextView.text = dataArray?[indexPath.row] //Set text for TextView
        return cell
    }
}
// MARK:- UICollectionViewDelegateFlowLayout
extension Keyboard : UICollectionViewDelegateFlowLayout {

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        sizeForItemAt indexPath: IndexPath) -> CGSize {
        //Setup grid like view
        //Device screen width
        let width = UIScreen.main.bounds.size.width
        //calculation of cell size
        return CGSize(width: ((width / 2) - 15), height: (collectionView.frame.height/2) - 20 )
    }

    func collectionView(_ collectionView: UICollectionView,
                        layout collectionViewLayout: UICollectionViewLayout,
                        insetForSectionAt section: Int) -> UIEdgeInsets {
        return sectionInsets
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumLineSpacingForSectionAt section: Int) -> CGFloat {
        return sectionInsets.left
    }
}

The only method in the delegate which notifies when input view button tapped. KeyboardDelegate:

func keyWasTapped(character: String)

DataSource has only one method which accepts [String] for data KeyboardDataSource

func dataForKeyboard()-> [String]
  1. Here we will initialize subviews and configure DataSource and delegate for collection view
  2. This is UITapGestureRecognizer receiver action depending on the tap it calculate selection for collection view
  3. We have added UITapGestureRecognizer to the TextView to get the selection

Usage

Use of this input view is pretty simple as we use other input views

    var keyboardView: Keyboard? //Custom view refrence
    override func viewDidLoad() {
        super.viewDidLoad()
        exampleTextView.layer.borderColor = UIColor.lightGray.cgColor
        exampleTextView.layer.borderWidth = 1
        //1
        keyboardView = Keyboard(frame: CGRect(x: 0, y: 0, width: 0, height: 216)) //Intialize custom input view
        keyboardView?.delegate = self //delegate
        keyboardView?.dataSource = self //datasource
        //2
        exampleTextView.inputView = keyboardView //Assign input view
        //Dismiss keyboard tap recognizer
        let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(ViewController.dismissKeyboard))
        view.addGestureRecognizer(tap)
    }
  1. Initialize keyboard view with frame and set its delegate and dataSource to self
  2. Assign Keyboard view to TextView inputView

We will have to implement KeyboardDelegate method confirm the protocol

    extension ViewController: KeyboardDelegate {
        func keyWasTapped(character: String) {
            //3
            //Insert charaters to the TextView
            exampleTextView.insertText(character)
        }
    }
  1. Here we will add selected text to our textview

if you want to toggle input views then you should add IBAction for the button

    //4
    //Toggle between system and custom input view
    @IBAction func chatButtonDidTapped(_ sender: AnyObject) {
        if(exampleTextView.inputView == nil){
            // replace system keyboard with custom keyboard
            exampleTextView.inputView = keyboardView
        }
        else{
            exampleTextView.inputView = nil
        }
        exampleTextView.becomeFirstResponder()
        exampleTextView.reloadInputViews()
    }
  1. This is button action to toggle between system and custom keyboard.

This is how we have built custom input view, the final output will look like as Final_Sample_gif

You can customize it with TableView, replace with images to select the image.

You can download complete sample from Here

Custom Picker

screenCustom Picker is an easy to use and customizable alternate to UIPickerView. It is written in Swift language. The Custom Picker started as normal UIPicker but it was to limited in its design and methods. Also, I want to achieve a flat-picker with selected area background customizable which was not possible with default UIPicker.

So I made a use UITableView and customize its scroll to get the look and feel of UIPickerView. With the use of UITableView, I have made the picker flat. Now the second limitation of UIPickerView i.e. non-customizable selected area, for this I used an overlay view and customize it according to my need.

Requirements

It requires Xcode 7.0+ and Swift 2.3.

Application Usage

Custom Picker includes a sample of the project of Unit Conversion where a user can select the to and from units and input the number in one UITextField and the output will be shown in other UITextField.

Create a new picker

To use this picker you have to instantiate the CutomPickerView like instantiate any normal UIPickerView and implements it CustomPickerViewDelegate and CustomPickerViewDataSource methods

    let leftPickerView = CustomPickerView(frame: CGRectMake(0.0, 0.0, self.contentViewOfLeftpicker.frame.width,  self.contentViewOfLeftpicker.frame.height))

    leftPickerView.delegate = self
    leftPickerView.dataSource = self

    self.contentViewOfLeftpicker!.addSubview(leftPickerView)

Implement the Delegate and DataSource

The delegate methods that needs to be overridden are

func customPickerView(customPickerView: CustomPickerView, titleForRow row: Int, forLabel label: UILabel) -> String

 func customPickerView(customPickerView: CustomPickerView, didSelectRow row: Int)

func rowHeightForCustomPickerView(customPickerView: CustomPickerView) -> CGFloat

func labelStyleForCustomPickerView(customPickerView: CustomPickerView, forLabel label: UILabel)

func imageStyleForCustomPickerView(customPickerView: CustomPickerView, forImageView imageView: UIImageView)

Firstly you must rowHeightForCustomPickerView(_:)

func rowHeightForCustomPickerView(customPickerView: CustomPickerView) -> CGFloat {
        return 50.0
    }

Then you have to implement titleForRow method it sets the title for each row in a picker

func customPickerView(customPickerView: CustomPickerView, titleForRow row: Int, forLabel label: UILabel) -> String {

        return (label.tag == -1) ? pickerDataFullForm[row] as! String : pickerDataShortForm[row] as! String
    }

Next is the method that provides the didSelectRow

func customPickerView(customPickerView: CustomPickerView, didSelectRow row: Int) {

        leftPickerView.labelUnitFull.text = pickerDataFullForm[row] as? String
        leftPickerView.labelUnitShort.text = pickerDataShortForm[row] as? String

    }

Next method is labelStyleForCustomPickerView method this method is used to give custom style to UILabel in CustomPickerView

func labelStyleForCustomPickerView(customPickerView: CustomPickerView, forLabel label: UILabel) {
        if (label.tag == -1) {

            label.textColor = UIColor.blackColor()
            label.font = UIFont(name: "HelveticaNeue-Bold", size: 20.0)
        }else{

            label.textColor = UIColor.lightGrayColor()
            label.font = UIFont(name: "HelveticaNeue-Bold", size: 15.0)
        }
    }

And the last delegate method is imageStyleForCustomPickerView this is used to give any background image to the overlay view.

    func imageStyleForCustomPickerView(customPickerView: CustomPickerView, forImageView imageView: UIImageView) {
        if customPickerView == leftPickerView {
            leftPickerView.arrowImage.image = UIImage(named: "LeftArrow")
        }
    }

CustomPickerViewDataSource

The CustomPickerView consists of only one data source method. This method returns the number of rows in that picker:

 func numberOfRowsInCustomPickerView(customPickerView: CustomPickerView) -> Int

iOS App Development trends in 2017

Apple has earned an income of $ 1.8 billion just in the applications and in-application buys over the New Year’s time of 2016. Apple App Store has alone assembled an income of $ 40 billion for the developers. This itself discusses the huge development that App Store has found in every one of these years furthermore for the developers.

Due to constant arrival of new gadgets and devices with varied features, the application engineers must be constantly on board updating as well as overhauled on learning in view of the latest patterns in versatile application advancement, for an increase in improvement in the zone of iOS application development.

Mentioned below are some of these iOS app development trends:

Swift Coding

Swift has picked up fame among the application developers for its comprehensive scope of systems and coding techniques. It deals with present day compiler foundation that empowers to compose solid codes utilizing Xcode instruments. As such, Apple’s Swift Programming has increased over Objective-C. Be that as it may, as Apple’s Swift went open source in 2015, there is an expanding number of clients embracing to Swift and this has surpassed the volume of clients for Objective-C.

There are many points of interest in Swift Programming, friendly codes and ease of learning as well as a lot of scopes to build, improvement, adapt and usability. 2017 will be a year which will see a select use of Swift 3.0, helping in the improvement of applications on iOS, watchOS, and tvOS. Swift will rise as the essential apparatus for creating Apple applications by supplanting Objective-C.

Applications driven by GPS and Augmented Reality

The little and the medium endeavors are progressively embracing area based versatile application improvement. This is advantageous in furnishing shoppers with data on items or administrations, surveys, examination of costs and a great deal more such exercises for versatile business.

GPS as a driver for portable application advancement was seen as the accomplishment of Pokemon Go in 2016. Be that as it may, we see a greater amount of these GPS-empowered applications in retail and robotization. The iOS application developers in 2017 and the years past will utilize a blend of AR and GPS.

Other application regions, for example, 3D Games will likewise observe the developers investigating the progressions on GPS innovation. As the clients open up to area based administrations, the fundamental sympathy toward the iOS application improvement is security,

Applications focussed on IoT

The quality of developers for IoT-based applications ascended by 34 % in 2016. We have seen an expanded income on the endeavors construct just with respect to IoT. The iOS application developers will attempt to exploit the market in light of Internet-empowered gadgets. The versatile application advancement on iOS will make esteem included applications for most extreme usage of the IoT items.

The concentration zones for iOS engineers in 2017 are the acknowledgment of signs from sensors in the IoT gadgets and in addition a safe trade of data over the Wi-Fi systems.

Security

iOS has picked up significance on account of its thoughtfulness regarding protection and security. Portable information security has grown up to a remarkable level, bringing on a range of sympathy toward the innovation goliaths. Apple has effectively stepped forward in the correct bearing as App Transport Security (ATS), which is to be made obligatory for the iOS applications. We will see more creative and more grounded information encryption innovations in 2017 and genuine endeavors are put into this range by the iOS application developers.

Undertaking Apps in light of iOS

There is a surge in big business portable application advancement and this is reliant on two components, constant client cooperation and engagement and progressively overseeing information and assignments.

There are numerous open doors that manifest for the iOS application developers in creating venture applications. Venture applications are getting based on CRM of the association, utilizing nimble approach.

There will be a mix of huge information, IoT and endeavor portable application advancement that will be progressively utilized for iOS application improvement.

The volume fight is constantly won by Android as there is a higher number of Android-based gadgets yet iOS dependably wins the race for acquiring more prominent income. In this way, income turns into a noteworthy motivator for iOS application improvement.

QICE is a leading mobile app development company in India helping clients to increase their business visibility over the mobile. In today’s technological world it is imperative that each company owns a mobile app. Nevertheless, just owning a mobile app of your company promoting your business won’t do wonders for your business.

It needs proper assessment,  designing, development, testing, and marketing. We are there to bring into being the mobile app that suits specific business needs.We have the expertise and the skills in developing the application for various platforms like iPhone, iPad, and Android.

Deploying with Deploybot

I vividly remember the first time, I messed up a production server. It was my early days of being a programmer, and we had got our first client.

Back then, my deployment strategy was basically to upload files using FTP and then run any commands on the server via the shell. During a routine deployment, I noticed a file which remained in the server, and in trying to remove it, I typed sudo rm -rf /.

On the Production.

I watched the next few minutes in horror as the entire client’s machine was wiped clean and the site went down. Fortunately, my client was understanding, and we had backups – so there was not much of damage – but I had to spend the next 3 days fixing the mess (and contemplating if I am really cut out for this job.)

My biggest learning from the incident was to be very careful when on Production. Over the time, I learned Git and other tools, which made deployments more easier and safer. As someone developing in Laravel, and leading a team of Laravel developers – I am always on the look out to make deployments easier.

And I have tried everything from custom bash scripts to git workflows, where we would git pull on server. None of them however stuck primarily due to the complexities they bought in

And after much experimentation – my team and I zeroed down to DeployBot.

DeployBot allows you to deploy code from anywhere. It takes your code from your Github / Bitbucket or self hosted Git repositories and deploys to any server. At QICE, we primarily use Digital Ocean and AWS – both of which are supported by DeployBot and make it an ease to integrate in our projects.

Here’s how DeployBot has helped us

Continuous Deployment

Over the day, we make 2-3 deployments to our sandboxes on certain projects. And these are fairly large commits. DeployBot seamlessly gets the new commits and automatically ( or manual for production setups ) deploys the latest files to the server.

My team now does not have to worry about deploying to server. All we have to do is push to a branch, and we know it will end up being on the server.

Rollbacks

Despite much preparation, there are moments, when things don’t work on the production for weird reasons. Deploybot has a rollback to a specific version feature, which is quite nifty at times like these.

Pre and Post Deployment Commands

After deployment, we run a few commands ex : Gulp, Migrations and Composer updates.

Deploybot allows us to specify what commands to run before and after deployment. That means, more developer peace and not worrying about switching to server and typing in each command on production machines.

Modifying Configuration Files

Even after all this, you may have to sometimes go to the server to edit your configuration files.

Deploybot eliminates this as well, by asking you to enter your configuration files. Just ensure all the changes are in your configuration file before you deploy, and they are deployed in your next deployment.

Notifications

Pretty much every web app these days has Slack / Email integration – and so does Deploybot. It notifies us everytime there is a deployment in our Slack channels.

No more informing the entire team that the production is done and they can resume their work.

Amazing Support & Reliability

This is something of importance to us. In the past one year, that we used Deploybot, we faced a downtime of exactly 1 minute, where we couldn’t deploy to production. We reached out to Support and got a reply back within the next minute telling us that the issue has been fixed.

Thanks to Deploybot, my team and I can now focus on building stuff than worrying about getting it to our customers. If you are into developing web apps, it is an invaluable part of your toolset and takes care of all your deployment worries.

Beginner’s Guide on using Nine Patch

When building Android apps, we use resource images with different densities – HDPI, MDPI, LDPI etc. But this soon gets tedious and hard to manage – and that’s where 9 patch images can help us.

Using the 9 Patch image library – we can include only one image ( the smallest one ) and the device will stretch it according to it’s need. 

Creating Nine Patch Images : 

  • Open terminal, go to Android Home Directory (the location where you unzipped the Android SDK) /Sdk/tools and execute command ./draw9patch to launch the nine patch tool.
  • qice@qice:~$ cd /home/qice/Android/Sdk/tools/
    qice@qice:~/Android/Sdk/tools$ ./draw9patch
  • Drag your PNG image into draw9patch window (Or select File > Open 9-patch to locate the file). Your workplace will now open.
  • The left pane is your drawing area, in which you can edit the lines for the stretchable patches. The right pane is preview area, where you can preview different shapes of stretched image.
  • Click within the 1 pixel perimeter to draw stretchable patches.Black lines on left and top of the image shows stretchable patch.Black lines on right and bottom of the image shows fillable area (which is optional).
    Here, Pink color shows a stretchable patch and Purple color in preview area shows fillable area. You can have as many stretchable sections as you want.
  • Now save your image, select File > save 9-patch
  • The image will be saved with extension .9.png

Using the 9 Patch Image : 

With the 9 Patch image that we just created, we could use it anywhere – and the advantage is the image will scale itself to adjust to the content inside.

9 patch-bg

For ex :  The image you see – the background is generated by the image that we just created. Note how it scales to fit different type of content.

<LinearLayout
	xmlns:android="http://schemas.android.com/apk/res/android"
	android:layout_width="match_parent"
	android:layout_height="wrap_content"
	android:orientation="vertical"
	android:paddingBottom="@dimen/activity_vertical_margin"
	android:paddingLeft="@dimen/activity_horizontal_margin"
	android:paddingRight="@dimen/activity_horizontal_margin"
	android:paddingTop="@dimen/activity_vertical_margin">

	<TextView
   	android:id="@+id/textView1"
   	android:layout_width="wrap_content"
   	android:layout_height="wrap_content"
   	android:layout_marginTop="15dp"
   	android:background="@drawable/bg_nine_patch"
   	android:gravity="center_vertical"
   	android:padding="10dp"
   	android:text="Text"
   	android:textSize="18sp"
   	android:textStyle="bold" />

	<TextView
   	android:id="@+id/textView2"
   	android:layout_width="wrap_content"
   	android:layout_height="wrap_content"
   	android:layout_marginTop="15dp"
   	android:background="@drawable/bg_nine_patch"
   	android:gravity="center_vertical"
   	android:padding="10dp"
   	android:text="Some large text"
   	android:textSize="18sp"
   	android:textStyle="bold" />

	<TextView
   	android:id="@+id/textView3"
   	android:layout_width="wrap_content"
   	android:layout_height="wrap_content"
   	android:layout_marginTop="15dp"
   	android:background="@drawable/bg_nine_patch"
   	android:gravity="center_vertical"
   	android:padding="10dp"
   	android:text="Bigger text. It gets stretch vertically as well as horizontally. See this background."
   	android:textSize="18sp"
   	android:textStyle="bold" />

	<ImageView
   	android:layout_width="wrap_content"
   	android:layout_height="wrap_content"
   	android:layout_marginTop="15dp"
   	android:background="@drawable/bg_nine_patch"
   	android:padding="10dp"
   	android:src="@drawable/orange_bag" />

</LinearLayout>

Pros of using 9 Patch : 

  • Reduces the app memory usage, as well as the entire size of APK.
  • Custom Backgrounds are now easy to make, without worrying about supporting a whole lot of device resolutions.