Showing posts with label iPhone. Show all posts
Showing posts with label iPhone. Show all posts

Saturday, July 13, 2019

Swift - Notify ViewController from AppDelegate On FCM / APN

Hello,

Recently I tried  my hands on iOS app after long time as I had to convert one of our hybrid app to native app on urgent basis. There I had webview where I was loading my html app. On FCM message receieved we need to send URL received in FCM to webview and load the URL.

So here in this blog I will mention the procedure for it.

First of all in AppDelegate we have didReceiveRemoteNotification method. There we will create notification for it. Here is the code.


let url = dict
serverURL = url;
let notificationName = Notification.Name("updateWebView")
NotificationCenter.default.post(name: notificationName, object: nil)

Now in the ViewController where you want to make updates, subscribe to this notification in viewDidLoad function.

override func viewDidLoad() {
  let notificationName = Notification.Name("updateWebView")
  NotificationCenter.default.addObserver(self, selector:            #selector(ViewController.updateWebView), name: notificationName, object: nil)
}

And then add function in ViewController.

@objc func updateWebView() {
  let appDelegate = UIApplication.shared.delegate as! AppDelegate
  let serverURL = appDelegate.serverURL
        
  guard let url = URL(string: serverURL!) else {
     print("Invalid URL")
     return
  }
        
  let request = URLRequest(url: url)
  webView.load(request)
}

That's it and now you will have data passed from AppDelegate to ViewController. This method you can pass any kind of data from FCM to respective ViewController.

Hope this helps you.



Monday, January 9, 2017

10 Years of iPhone

Today is the one of the historical day for IT industry. Ten years ago today, on Jan. 9, 2007, Apple co-founder Steve Jobs, unveiled the product that would drive Apple to become the most valuable company in the world and cement Apple’s comeback as the greatest in business history. At the Macworld conference in San Francisco, he unveiled the iPhone.


Here is his Key note speech, in which he introduced iPhone.





Off course there was something crazy about iPhone. It changed mobile industry entirely and introduced Mobile Application economy with introduction of App Store, where developers can upload their apps and can make money. That created entire new opportunities for mobile application developers. Since it's introduction there are number of versions of iPhone are introduced with exciting features and cool UI display.

Being a mobile application developer I daily work with iOS devices and also other mobile devices here are some points which I feel are very spacial in iPhone.

Very Stable OS and Hardware support


Being a mobile application developer I work with both android and iOS devices but at one point every developer has to struggle with android while dealing with hardwares such as camera or SD card or any other native features. While in iPhone this is usually not the case because it has stable SDK and hardware which are manufactured by only Apple so we don't see much changes and customizations. While in case of android, since it's an open source operating system all the phone manufactures have changed it and customized it as per their platform. So face bit of problems while working with hardware. One app working without any issue in one phone may not work in other phone. While in case of iPhone, app will work all the devices and all the iOS versions.


Nice Development tools like Xcode IDE and Simulators


This is another advantage iOS development we have very stable Xcode IDE and iOS simulators using which we can develop applications very easily. In most of the cases you don't need real devices. Using simulators you can easily develop and test apps and launch in apple store. Xcode is not changed much since it's introduction and it's very easy to use, yes with the introduction of Swift, we have to learn new languages not but that's ok, that change is good.


It's not like iPhone is good in all the cases, there are some drawbacks.

Tooooo Expensive


This is first and foremost drawback for mobile application developer. Some features if you want to test like push notifications or cameras, that will work only in real devices and you have to buy it and it's too expensive for the developers. Developers can hardly afford one or two devices not more than that. Due to which sometime it gets hard to test some apps. As a mobile app developer I am still dreaming of having my own iPhone since years but I didn't manage to get it yet.

Bit Complex Testing Process and Publication Process


Compare to android, testing and publication process is bit complex in case of iOS. For Android you can share APK with any android devices and it can be installed and tested easily. While in case of iPhone, you need  apple developer account and create developer certificate and provisioning profile and register device Ids and upload app for testing and get it approved before you can send it to someone for testing using TestFight. Also to publish the app in market, you have to maintain some standards in case of UI and features, otherwise it's possible that your app may be rejected by app store and you have to redo again and make changes and republish app.


In short being a developer sometimes iPhone looks like blessing and sometime we feel that

Life Was Much Easier When Apple And Blackberry Were Just Fruits


Here is one funny video about it, Have fun and happy coding.


Saturday, December 10, 2016

Cordova Application Hanging During Startup on iOS 10

Hello,

If you have any cordova application in iTunes, you may have faced this issue since launch of iOS 10,. Either your app hangs at Start up or it will hang in case when there is a use of any plugin, like camera or location or any other native features. 

This is because of content security policy. iOS 10 needs content security policy where you have to mention what types of content you will allow to load.

As you have notice cordova plugins are invoked gap:// and in iOS 10 it's not allowed by default so you have to mention this in content security policy. 

Add following line in head section of your index.html file.

<meta http-equiv="Content-Security-Policy" content="media-src *; img-src * data:; font-src * data:; default-src  * gap:; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">


As you can see we have added gap: in allowed content src along with other source, now your app will work normally in iOS 10.

Hope this helps you.

Thursday, February 19, 2015

iOS Cordova Get Device Name

Hello,

Recently in one of my iOS app project, I had a requirement to get device name like "Hiren's iPhone". First I thought it's pretty simple as I checked device API documentation and saw that there is method device.name which should gave device name. I tried that and surprisingly it was returning undefined. I was not sure why it's not returning result. Then I saw source code and found out actually name property is not added in device API so I decided to add it. In this blog I am going to explain how to do this.

First open your CDVDevice.m file and find following function.


- (NSDictionary*)deviceProperties

In this function add following new line. 

[devProps setObject:[device name] forKey:@"name"];

That's it on objective C side. Now lets modify on JavaScript side. Open device.js file inside plugins/org.apache.cordova.device folder in your www folder. There is a constructor function 

function Device()

In this function first add name property. 

this.name = null;

And inside following function initialize this property.

channel.onCordovaReady.subscribe(function() {
        me.getInfo(function(info) {
        }
}

me.name = info.name;

That's it and now device.name should return your name of device set in settings.

Tuesday, February 17, 2015

iOS Today App Extension Widget Tap To Open Containing App

Hello,

Recently I added Today App Extension to one of my iOS app. In that we have a requirement to open containing app when user taps anywhere in app extension view. In this blog I am going to explain how to do this. First you have to add tap gesture recognizer to your main container view. In my case I had UIView as base container view. Inside this view I have added all other views.

So first create iboutlet property for that view. Now create Single Tap Gesture Recognizer.

UITapGestureRecognizer *singleFingerTap =
    [[UITapGestureRecognizer alloc] initWithTarget:self
                                            action:@selector(handleSingleTap:)];

[mainContainerView addGestureRecognizer:singleFingerTap];

As seen in above code, first we created singleFingerTap recognizer and added this as gesture recognizer to mainContainerView. Now add following function which we mentioned in selector.

- (void)handleSingleTap:(UITapGestureRecognizer *)recognizer {
    NSURL *pjURL = [NSURL URLWithString:@"AppUrlType://home"];
    [self.extensionContext openURL:pjURL completionHandler:nil];
}

That's it. Simple.. isn't it? But wait, it won't work as we have to add URL type in our app. In iOS you can define custom URL schemes and URL types for your app. Using which you can open your app from browser or from some other app using openURL function as shown above in code. So let's add custom URL type for your app.

Open plist file of your main app and add new item with name URL types, expand item 0 of it and add new item with name URL Schemes. Expand item 0 of URL Schemes and add  "
AppUrlType" as a value. For your application, you can use any valid name. After adding this, you should have following structure in your plist file.


That's it. Now select your App Extension Target and run the widget. Tap anywhere in your widget and it will open your containing app. 

iOS App UI not updating in Main Thread

Hello,

Recently in one of my projects, I faced a very strange issue. I have an http service call in app which was in background which brings some data. I want to show those data in Textviews in UI. Now the issue was it was not updating UI properly. I had five textviews and five strings in five variables. Out of which it was updating only one Textviews. Rest of the views were not updated. I was not sure what was the issue here as I was updating UI on main thread but still it was not working. See the below code.


NSString *value1 = [jsonArray objectForKey:@"key1"];
NSString *value2 = [jsonArray objectForKey:@"key2"];
NSString *value3 = [jsonArray objectForKey:@"key3"];
NSString *value4 = [jsonArray objectForKey:@"key4"];
NSString *value5 = [jsonArray objectForKey:@"key5"];

As you see in above code I set five variables from my array which were created from JSON response of web service. Now I used dispatch_async to go on Main thread and set values to Text views.

dispatch_async(dispatch_get_main_queue(), ^{
       [txt1 setText:value1];
       [txt2 setText:value2];
       [txt3 setText:value3];
       [txt4 setText:value4];
       [txt5 setText:value5];
});

As I mentioned an issue above that, it was setting value of only first text views. Others were blank. So I was not sure what was the issue. Later I realized that it was nil problem. Since I used local variables to store data, by the time my code inside dispatch_async runs, the scope of those variables were destroyed and there was a nil value. So other text views were blank.

So the solution was to keep variable initialization inside  dispatch_async method. See the below code.

dispatch_async(dispatch_get_main_queue(), ^{
       NSString *value1 = [jsonArray objectForKey:@"key1"];
       NSString *value2 = [jsonArray objectForKey:@"key2"];
       NSString *value3 = [jsonArray objectForKey:@"key3"];
       NSString *value4 = [jsonArray objectForKey:@"key4"];
       NSString *value5 = [jsonArray objectForKey:@"key5"];

       [txt1 setText:value1];
       [txt2 setText:value2];
       [txt3 setText:value3];
       [txt4 setText:value4];
       [txt5 setText:value5];
});

That's it, it worked. After having initialization inside  dispatch_async method, all the text views values were displayed properly. Hope this will help you and save you time.

iOS Share Data Between iOS App and Today Widget (App Extension)

Hello,

Recently in one of my projects I implemented a Today Widget for the iOS application. While working on that I faced a situation where I have to get data stored in User Defaults of Main app to Today Widget. In this blog I am going to explain how you can sync data between app and widget.  In my case it was simple string data that was stored in user defaults.

For this, first you need to create an app group from Xcode. App group is group of apps which contains main app and an extension. When you create a group from Xcode, it will also create a group in developer portal. For that, first click on project in project explorer and select your main app target in Xcode and go to Capabilities - > App Groups. Initially app groups will be off, first you have to make it on and it will show a pop up window where you can create a new group. Group name always starts with group. prefix. See the image below.


Add your new group like this: group.companyname.groupname and click on Ok. It will sync with developer portal and create app group. Now select your app extension target and go to Capabilities - > App Groups. It will be off first. On it and it will sync with existing app groups which we created in first step. Add your app extension to this group. That's it. Now you can share data between app and app extensions. Now you have to add data by creating group defaults and saving data to groups. See the following code.  This code you can add to your main app.

NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:@"group.company.GroupDefaults"];
[shared setObject:[defaults objectForKey:@"key1"] forKey:@"value1"];
[shared setObject:[defaults objectForKey:@"key2"] forKey:@"value2"];
[shared synchronize];

As you can see in above code, we have created NSUserDefaults class instance with suite name or the group. Every time after adding objects to NSUserDefaults, you have to synchronize it. Else data will not be saved. Add following code to your app extension where you want to read data. 

NSUserDefaults *shared = [[NSUserDefaults alloc]initWithSuiteName:@"group.company.GroupDefaults"];
self.value1 = [shared objectForKey:@"key1"];
self.value2 = [shared objectForKey:@"key2"];

Also you can save other data in app extension and can read it in main app. 

[shared setObject:[defaults objectForKey:@"key3"forKey:@"value3"];
[shared setObject:[defaults objectForKey:@"key4"forKey:@"value4"];
[shared synchronize];

As I mentioned above, every time you have to sync after adding or modifying data in user defaults. Hope this will help you.



Friday, May 16, 2014

Ad hoc App Installation Failed in iOS Devices

This blog post is about the recent problem I faced in installing Ad Hoc application in iOS devices. Recently I was working with a app where I generated add hoc iPA file for the distribution on registered devices. But some how it was not installed on registered devices. When you try installing application with iTunes, it starts installations and after couple of minutes it stuck and never finish installation. It took some time to figure out the issue so here in this blog I will explain this.

So when you face this situation and if you see the device log you will find following error in it.

install_application: Could not preflight application install

That means something is wrong with installation and most probably it's the issue of the provisioning profile you are using. For that first clean the build from Xcode. Check the device id in list of the registered devices. If it's not there add it and regenerate your distribution profile. Now go to Xcode and select the project and go to general tab. Make sure you have added the apple developer account and selected the correct team.
 Now go to Build Settings tab and go to Code Signing section. Make sure you have selected correct distribution certificate for release and selected correct distribution profile. See the screenshot attached below.


Here if you have selected development provisioning profile and then it will not work so right selection for code signing identity and provisioning profile is must. Now you can generate archive and export the iPA file when you sync it with iTunes it will get installed properly.  Hope this will help you.

Monday, May 12, 2014

iOS 7 Phonegap Change Background Color of Status Bar

Hello,

Recently I was working on Sencha Touch, Phonegap application where we have a requirement to change background color of top status bar of iPhone where we have carrier, wifi and battery symbols. There are two ways to do it. In this blog I will explain both the steps.

First Step

In iOS 7 if you have status bar visible your UI will overlap the status bar and we will take advantage of it. First select your project and go to Deployment info. Make sure you have Hide during application launch checkbox and set status bar style as default.

Now your webview will overlap the UI and the status bar will be transparent. So we can add a component on top of our page with height 20 pixel and preferred background color so your status bar will have same background color. For example I added docked panel in Sencha Touch with fixed height and background color in my main container. 

Ext.define('MyApp.view.LaunchView', {
    extend : 'Ext.Panel',
    xtype : 'launchmain',

    config : {
        layout : 'card',
        
           items : [{
                    xtype: 'panel',
                    docked: 'top',
                    style: {
                        'background-color': '#34495E',
                        'color':'#ffffff'
                    },
                    height: 20
                    
           }]
    }
});

Since this is may main container all the views added in this container will have this panel and top. Now issue could be if you have some external pages loaded in app on which you don't have control then this panel will not be there you can not have top component with background color. For that follow step 2

Second Step

Here in this step we will add component on top of our webview in our main iOS 7 view. Hence it will be available throughout the app. For that add following code in didFinishLaunchingWithOptions method of AppDelegate.m

 if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7.0) {
        UIView *topView = [[UIView alloc] init];
CGRect screenRect = [[UIScreen mainScreen] bounds];
        topView.frame = CGRectMake(0, 0, screenRect.size.width, 20);
        topView.backgroundColor = [UIColor colorWithRed:52/255. green:73/255. blue:94/255. alpha:1];
        [self.window.rootViewController.view addSubview: topView];
    }

Here we are added another view with required background color on top of webview. Now we have to shift down webview for 20 pixel so that this view would be visible. For that add following code to viewDidLoad function of your MainViewController.m file. 

if ([[[UIDevice currentDevice] systemVersion] floatValue] >= 7) {
        CGRect viewBounds = [self.webView bounds];
        viewBounds.origin.y = 20;
        viewBounds.size.height = viewBounds.size.height - 20;
        self.webView.frame = viewBounds;
    }

As you can see in above code we are changing the origin of webview and shift it 20 pixel down. You can simply add above code to avoid overlapping of UI.


Friday, January 31, 2014

Convert your Magento Store to Mobile Store and Mobile Web Application (Magento Mobile)

Do you have a Magento store and you want to reach to maximum number customers? Then read this blog.

As we know that mobile revolution has changed the world. Number of people are using smart phones and tablets now a days for day to day work. They use mobile internet for almost everything. So your customers may browse your magento store from mobile devices and if your store is not optimized for mobile, it may not load on mobile, or have some issue. Hence users may not be able to buy products on your store and eventually you lost your customer. Now lets see in details, why you need separate mobile web app for your store.

1) Limited Screen Size

On mobile devices screen size is limited so we don't get much space like desktop computers to show data. In very small space you have to effectively show the content to user so user can easily read it and see it. Many magento stores have this issues. As the site is optimized for desktop only, so the content is not visible properly.

2) Limited BandWidth

Generally mobile networks are slow you your magento store may take time to load. As we know that for each magento page there are some CSS some JS files. There are plenty of images, banners etc. Every time when user navigate on your magento store there is considerable delay in loading resources of the page. This may slow down performance on the mobile devices. Some of the users don't like slow websites.  If we use responsive mobile theme, we can improve the layout performance but still we have delay in page refresh

3) Different Resolutions

As we know that there are mobile devices with different screen resolutions. For example iPhone has high resolution retina display. Some of the android phones also support HD graphics. While some mobiles does not support HD graphics. In this scenario your assets like images, CSS should support high resolution and normal resolution. So if you don't support high graphics, your website does not look good on high resolution devices.

So how to solve all above problems and optimize your magento store for all the mobile devices? We have a solution for that. We have built an JavaScript/HTML 5 /CSS 3 based application for magento stores. This application has following features. With our solution your magento store is easily converted to Magento Mobile Store.

1) Responsive layout to fit all the devices.
2) Support all types of touch gestures
3) Show resources based on resolution
4) Rendering engine to support landscape and portrait orientation
5) Have services to load data instead of page refreshes.
6) Supports private browsing
7) Slide navigation for menus
8) Support for local storage of data
9) Supports all types of magento products
10) Customized from same magento admin
11) Optimized for best speed and performance.
12) Rich user interface

Our solution is completely build in HTML and JavaScript. So once the application is loaded. There is no page refresh. All the navigation is local navigation. Data is coming via Ajax request with JSON format. It drastically reduces the network usage. It uses space such a way that you will see the clear information about products and content.

Don't believe it? See the difference
This is our recent implementation in one of the biggest magento store. Following is the regular desktop site in iPhone.

As you see that it looks bit cluttered in iPhone. None of the content is visible unless you zoom in. So to read the content properly, you have to zoom in and zoom out. After zoom in you have to scroll left and right to see the content properly.Now lets how our mobile web app for magento looks in mobile browser.


Pretty cool right? With our application your magento store look like mobile web application in mobile phones and users have easy to use navigation, clear content, rich media, high resolution graphics, high performance. When you implement our solution, your users will still see the desktop site when they view it on desktop browsers. But they will see above mobile app when they visit your store from mobile browser.

Want this app for your magento store? Contact me right away.

Email : hdave10@gmail.com
Skype: hiren.dave
Phone: +91-9327452580

Monday, May 13, 2013

Passing Query String With Index.html file in iOS Phonegap (Cordova)

Hello,

Imagine a scenario that you have Sencha Touch/ jQuery mobile application and you have used Phonegap (Cordova) to compile it to native iOS application.  Now your application expects some params like authentication token, or user id or anything it can be. You need to send this params along with your index.html file so that you can use it in app launch function. Have you ever faced this situation. If yes then here is the solution. Please remember this solution is specifically for iOS Cordova application.

First let's see how normally it works. When you create a Cordova based application in XCode, You have AppDelegate.h and AppDelegate.m file. Open AppDelegate.m file and find a function below.


- (BOOL) application:(UIApplication*)application didFinishLaunchingWithOptions:(NSDictionary*)launchOptions

In this function find the following lines of code.

self.viewController.wwwFolderName = @"www";
self.viewController.startPage = @"index.html";

This specify that web assets folder is WWW and start page is index.html. If you have some other start page you can change the name here. Now if you try to pass query string as follow, it will not work.


self.viewController.startPage = @"index.html?query1=value1";

Because it treats it as page name and there is no such page. So how to resolve this.

First of all remove the start page name from code.

self.viewController.startPage = @"";

Now we will implement NSURL interface and add some custom functions in it to handle the query string. Add following code to your AppDelegate.m file above implementation of AppDelegate

@implementation NSURL (Additions)

- (NSURL *)URLByAppendingQueryString:(NSString *)queryString {
    if (![queryString length]) {
        return self;
    }
    
    NSString *URLString = [[NSString alloc] initWithFormat:@"%@%@%@", [self absoluteString],
                           [self query] ? @"&" : @"?", queryString];
    NSURL *theURL = [NSURL URLWithString:URLString];
    [URLString release];
    return theURL;
}

@end

This function accepts query string and add it to URL and create new URL. Now add following code at end of didFinishLaunchingWithOptions function.

NSString* newQueryString = @"query1=value1&query2=value2&query3=value3";
NSURL *newurl = [NSURL fileURLWithPath:[[NSBundle mainBundle] pathForResource:@"index" ofType:@"html" inDirectory:@"www"]];

newurl = [newurl URLByAppendingQueryString:newQueryString];
[self.viewController.webView loadRequest:[NSURLRequest requestWithURL:newurl]];


Above code will build custom URL with query string and load the URL in iOS webview.

Hope this helps you.




Saturday, September 1, 2012

Send HTTP Request and retrive HTTP response in iPhone, iPad Application

Hello,

Recently I was working on an iPhone application where requirement was to send HTTP request and retrieve the response. This was not a JSON or restful web service. Checkout the following code.


 NSMutableString* url = [NSMutableString string];
    [url appendString:@"http://www.example.com"];
    NSURLRequest *theRequest=[NSURLRequest requestWithURL:[NSURL URLWithString:url]
                                              cachePolicy:NSURLRequestUseProtocolCachePolicy
                                          timeoutInterval:60.0];
    NSURLConnection *theConnection=[[NSURLConnection alloc] initWithRequest:theRequest delegate:self];
    if (theConnection) {
        
        
    } else {
        UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Failed" message:@"Check your networking configuration." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
        [alertView show];
    }

Above code will initiate the connection. If it's successful it will go in if part else it will go in else part. On successful connection we have to retrive the data so we will add few delegates functions for it.

- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response {
    NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
       if ([httpResponse statusCode] >= 400) {
        // do error handling here
           UIAlertView* alertView = [[UIAlertView alloc] initWithTitle:@"Failed" message:@"Check your networking configuration." delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil];
           [alertView show];
    } else {
        // start recieving data
    }
}

This function will be invoked when we have response. After we get response we will start fetching data. There is a separate delegate function for it.

-   (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)theData{
    NSString *response = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];

Above function will be invoked when we will have real data. Here response will give us data in string format.

Hope this helps.

Wednesday, August 15, 2012

iOS, iPhone, iPad, XCode resize view on rotation

Hello,

This is quick blog on how to resize view in iPhone, iPad application. Normally when we use story board all the views we add are of portrait mode and if your app supports rotation, in landscape mode you need to resize your views. So how to do that.

Go to your ViewController file and find the following function.


- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation

Normally function will look as following.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return (interfaceOrientation == UIInterfaceOrientationPortrait);
}

That means it will only support Portrait orientation. So to allow rotation in your app change this function as follow.

- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}

Now it will allow rotation in application. Now add one more function to your view controller file

- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation{
    if (fromInterfaceOrientation == UIInterfaceOrientationPortrait) {
           //
    }
    else{
    }
}

This function will be invoked automatically when orientation of phone changes. fromInterfaceOrientation will give you the last orientation. That means if you are in porttrait mode and you are now changing to landscape mode, value of fromInterfaceOrientation would be UIInterfaceOrientationPortrait. So in above function you need to reize your view in if else loop.

Hope this helps you.