Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / Mobile / iPhone

How to Use libphonenumber for iPhone Apps

5.00/5 (1 vote)
4 Sep 2012CPOL3 min read 26.8K  
Use libphonenumber in iphone apps in an efficient and clean way

Introduction

I am a founder at a startup that needs a way to format and work with mobile phone numbers on the iPhone. For a while, I was searching for a library that would help me and found, like many others, Google's libphonenumber.

The problem is that the library has no ready made variant for the iPhone, so I was faced with 2 choices, taking the validation code to the server side or trying to compile the C++ variant of the library for iPhone.

I wasn't pleased with either, and then I thought about the JavaScript implementation of the library and decided to use that.

Adding the JavaScript variant of the libphonenumber library to an iPhone app is easy, but there are some problems with that:

  1. libiphonenumber is dependent heavily on the closure library so you have to add that also to your project or let the UIWebview control download all of the js files that he needs, this of course implies that you can only use it when you are online !
  2. The performance of using the JavaScript variant of the library are very poor because there are many sparsed js files and the scripts are long and not optimized.

Now the internet is filled with half solutions and dead end 10 line answers, but I am going to show you how to compile and use libphonenumber in your iPhone apps in an efficient and compact way.

Background

I demonstrate the use of the library by implementing a JavaScript method by the name of buildAndValidatePhone which validates a mobile phone number taking his country code into consideration and returning his international format or the string "invalid" in case of error.

You should add methods to the JavaScript side and call them from your app side as I demonstrate, read the libphonenumber documentation it is a powerful library.

Using the Code

What I've done is to create an hidden UIWebview control in my app that is loading a compiled JavaScript file.

The JavaScript file calls the libphonenumber JavaScript implementation but it is a squeezed file with all of the dependencies, like the closure library, that libphonenumber needs.

The app invokes JavaScript calls, in our example we call the method buildAndValidatePhone, and get's the results that it needs, in the example below, I will show you how to call a method that will check if a mobile phone number is valid, and you can take it off from there.

Ok, enough talking, let's cut to the chase.

  1. First, let's examine the JavaScript file itself and what to do with it:
    JavaScript
    // ==ClosureCompiler==
    // @output_file_name default.js
    // @compilation_level SIMPLE_OPTIMIZATIONS
    // @use_closure_library true
    // @code_url 
    // http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/metadata.js
    // @code_url 
    // http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonemetadata.pb.js
    // @code_url 
    // http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonenumber.pb.js
    // @code_url 
    // http://libphonenumber.googlecode.com/svn/trunk/javascript/i18n/phonenumbers/phonenumberutil.js
    // ==/ClosureCompiler==
    
    goog.require('goog.dom');
    goog.require('goog.json');
    goog.require('goog.proto2.ObjectSerializer');
    goog.require('goog.array');
    goog.require('goog.proto2.PbLiteSerializer');
    goog.require('goog.string');
    goog.require('goog.proto2.Message');
    goog.require('goog.string.StringBuffer');
    goog.require('i18n.phonenumbers.NumberFormat');
    goog.require('i18n.phonenumbers.PhoneNumber');
    goog.require('i18n.phonenumbers.PhoneNumberUtil');
    
    function buildAndValidatePhone(phoneNumber, countryCode) {
        var strIntlNumber = "invalid";
        
        try {
            var phoneUtil = i18n.phonenumbers.PhoneNumberUtil.getInstance();
            var regionCode = phoneUtil.getRegionCodeForCountryCode(countryCode);
            var number = phoneUtil.parseAndKeepRawInput(phoneNumber, regionCode);
            
            if (phoneUtil.isValidNumber(number)) {
                var PNT = i18n.phonenumbers.PhoneNumberType;
                var numberType = phoneUtil.getNumberType(number);
                
                if (numberType == PNT.MOBILE) {
                    var PNF = i18n.phonenumbers.PhoneNumberFormat;
                    strIntlNumber = phoneUtil.format(number, PNF.E164);
                    strIntlNumber = strIntlNumber.replace('+','');
                }
            }
        }
        catch(ex) {
        }
            
        return strIntlNumber;
    };

    You should copy the content of the file and paste it in the closure compiler page:

    Just copy/paste the JavaScript above instead of the text in the editor of the compiler and press build.

    The compiler will find all of the references that libphonenumber is having with the closure library and create one squeezed JavaScript file.

  2. Download the JavaScript file to your local disk and change its extension from js to txt, this is crucial because XCode doesn't like js files, it treats them like source code and not like resource files.

    In our example, I have called it: libphonenumber.txt, Drag the file into XCode and add it to the project.

  3. Use the code snippet below to load the JavaScript file into a UIWebView and call our JavaScript method, something like this:
    JavaScript
    UIWebView *_webView = [[UIWebView alloc] init];
     _webView.delegate = self;        
     NSString *htmlString =  [NSString stringWithString:@"<html>
    <script type='text/javascript' src='libphonenumber.txt'></script></html>"];
    [_webView loadHTMLString:htmlString baseURL:[NSURL fileURLWithPath:
    [[NSBundle mainBundle] resourcePath]]];  
  4. Make sure you implement UIWebViewDelegate webViewDidFinishLoad and use the code snippet below to call our JavaScript method from objective C:
    JavaScript
     - (void)webViewDidFinishLoad:(UIWebView *)webView
    { 
        NSString *mobileNumber = @"0541234567";
        int countryCode = 972; 
        NSString *formattedCall = [NSString stringWithFormat:
        @"buildAndValidatePhone('%@', %d);",     mobileNumber, countryCode];
        NSString *formattedNumber =[_webView stringByEvaluatingJavaScriptFromString:formattedCall];
        NSLog(@"result: %@", formattedNumber); 
    }   

I am always amazed at how hours and hours of work translated to half a page of code at the end.

I hope this tip will be of an interest to someone, I'm sure it will...

Enjoy!

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)