June 11, 2008

Hybrid Mac applications

Posted in misc tagged , , , , , , , , , , at 10:45 pm by tetontech

The code example here is now included in a framework called QuickConnectiPhone.  If you want to know more have a look at this post as well as others in this blog.

In a previous post I showed how a UIWebview can be programmatically inserted into an application running on the iPhone using the new SDK.  In this post I will explain how to insert a WebView into a Cocoa application running on the Mac.  This example will show how to use the new Interface Builder that ships with the new SDK.  I will also cover this soon for the iPhone.

There are a series of step that you should go through to accomplish this task.  The names for items created in this example should be replaced with what you want them to be.

Steps:

  1. Select ‘New Project’ in the file menuThe project type selection window
  2. Select the ‘Cocoa Appliction’ project template
  3. Name the new project.  Mine will be called ‘example3’entering the name of the new project
  4. Create and name a new Objective-C file.  I will call mine AppDelegatethe Cocoa file creation window
  5. Open AppDelegate.h and add ‘IBOutlet id webView;’ to the class.  This is the name that will be associated with the WebView that we will later drag and drop when we are using Interface Builderadding an outlet to the header
  6. Add the WebKit Framework to the project.  On my machine this is located in
    ‘/Developer/SDKs/MacOS10.5.sdk/System/Library/Frameworksthe dialog used to select the WebKit framework
  7. Open the MainMenu.xib file by double clicking it.  This will open Interface Builder.  The xib file is found in the Resources group in your project.
  8. Open the library window by selecting it in the ‘Tools’ menu.
  9. Drag the ‘Object’ cube from the library to the ‘MainMenu.xib’ windowa screen shot showing an Objective-C object being added to the xib file
  10. Select ‘identity’, the ‘i’ tab in the inspector window labeled ‘Object identity’ and change the Class to be ‘AppDelegate’ or what ever you named the Objective-C class you created in step 4.  This will create a link between the xib file and the Objective-C class.  Notice that as soon as you rename the class the id you created in the header file in step 5 is now listed for the object in Interface builder as an outlet.  This is what will allow us to gain access to the WebView we will soon create in Interface Builder.rename the object to link it to the Objective-C files created earlier.
  11. Add a WebView to the ‘Window’ window by selecting ‘Web Kit’ from the ‘Objects’ tab of the library window and then dragging the WebView element to the ‘Window’ window.  A WebView will now appear in the ‘Window’ window that you can resize and locate anywhere in the window you would like.  I will make mine slightly smaller than the containing window.  You will also want to select the ruler tab in the ‘inspector’ window.  By clicking on the light red arrows within the box in the ‘Autosizing’ section your WebView will stretch as the window stretches.placing the WebView element in the main app window
  12. Select the App Delegate item in the MainMenu.xib window and display the connections tab, select the ‘->’ in the blue circle. A small circle will exist to the right of the outlet ‘webView’.  Drag it onto the WebView in the ‘Window’ window.  This will cause an outlet connection to be made.  This means that in the code your Xcode Objective-C code the ‘webView’ you added to the header file in step 5 will in essence be a pointer/reference to the WebView you created in Interface Builder in step 11.linking the WebView to the outlet
  13. In the ‘Referencing Outlet’ section of this same inspector window for the App Delegate there is a line that says ‘New Referencing Outlet’.  Select the small circle on the right and drag it over ‘Files Owner’ in the ‘MainMenu.xib’ window.  A popup will be shown that says ‘delegate’.  Select it.  You class ‘App Delegate’ will now be used as the delegate for the application.  This will allow you to now create functions that are triggered for events that happen in the application.  Step 14 will be the implementation of one of these.linking the AppDelegate class to be the delegate for the application
  14. Save the you changes by saving within Interface Builder.
  15. Implement the applictionDidFinishLoading method in AppDelegate.m.  This is where you can write out to the log file using NSLog and tell the WebView to load a specific web page as well as other actions you may want to have happen when the application has completed loading.  In this example we will load a page found locally on the machine that is part of the application itself.  It is called ‘index.html’ and can be found in the ‘Resources’ group in the Xcode project.  The code in the image shows you how to load this web page.implementing the application Did Finish Launching method
  16. Compile and select the ‘Build and Go’ icon to run the application.the application running
Advertisements

11 Comments »

  1. Mike Farmer said,

    Woohoo! This is great! I can’t wait to give it a try. Thank you for posting this.

  2. Keith said,

    I seem to be getting 2 warnings when I “build and go”:
    warning: no ‘-mainFrame’ method found
    warning: no ‘-loadRequest:’ method found

    Can anyone shed some light? if anyone can email me the code I would be very grateful I’m at keith0103 at yahoo dot com

    Thanks,
    Keith

  3. Keith said,

    I meant keithg0103 at yahoo dot com

  4. tetontech said,

    Keith,

    It sounds as if you missed or incorrectly implemented the step (12) where the WebView object in Interface Builder is linked to the webView outlet. Check the log file. It should have a line in it that is the result of executing line 15 of the AppDelegate.m file. The log file line should read
    ‘hello ‘ with a different hex memory location for your WebView object. If it states the type of the object is not WebView or is nil then you need to redo step 12.

  5. Keith said,

    Thanks for the file Lee, I see where my mistake was made. There was a problem with in step 12. All works now.

  6. Dave said,

    Excellent advice! I’ve been following all of the UIWebKit tips on here for a few days now – keep them coming 🙂

    There’s one thing I’ve yet to work out how to do. Do you know if there’s a way to call back into the UIWebView view controller from JavaScript? I don’t mean the sqlite access, but an actual call to a Cocoa function (passing over some parameters, ideally) from javaScript. Any ideas? This would enable NSLog calls triggered by javaScript (amongst many other things).

    Thanks for any help!

    Dave.

  7. tetontech said,

    When I first started using the UIWebView I looked for this functionality but was unable to find it. I have come to the conclusion that it was left out the the UIWebView on purpose for security reasons. Since the UIWebView can run outside of a browser it doesn’t have the protection of the security features that are part of the browser such as the same origin policy. This policy states that the XMLHttpRequest object can only retrieve information from the same place as it originated. This limitation makes XSS, cross site scripting, attacks harder to accomplish.

    You can imagine the security mess if javascript was able to make calls down into the Objective-C of an application if malicious JavaScript was retrieved and executed on your phone.

    This UIWebView behavior is different from the WebView behavior used in a Mac application. It will allow you to log javascript errors, which is what I really wanted to have available to me. I assume that this was not included in the UIWebView for security reasons as well.

    This limitation is why I suggest using Dashcode to do as much creation and debugging for hybrid apps as possible before moving them over to Xcode.

    All in all, I can live with the limitations caused by these security decisions in exchange for the ability to use the XMLHttpRequest object to get data from multiple servers within one application.

  8. Dave said,

    Thanks for the response. I had wondered if it might be a security thing. I’ve submitted a feature request for it anyway – you never know.

    My app is an existing web app that is equally at home in Safari, so most of the debugging can be done there and then simply removed for the iPhone UIWebView version, I guess.

    One thing I was hoping to use this for was for a replacement for JavaScript alerts, which don’t seem to do anything from within UIWebView. Have you found a way to perform an alert? My alternative is to use a hidden div with a high z-index to create my own.

    Thanks for the advice,

    Dave.

  9. tetontech said,

    Alerts, while they look like JavaScript, are actually a native implementation of the browsers. Because of this they are not recognized in the UIWebView. In fact, as I am sure you know, alerts are strongly discouraged for user notification. The best option is it re-evaluate why the alert is there and see if using DHTML could be used instead.

    Since the JavaScript can’t call Objective-C on the iPhone, unless you are using the forbidden API’s, there is no way to ‘pop up’ an alert like dialog at this time.

    Instead of alerts for debugging i create a div that I float right or left to remove it from the rendering order and then append my debug messages to its’ innerHTML. I also use the stepwise debugger in Firefox and WebKits’ developer menu or Dashcode. Between these tools I can usually do what I need to when debugging code.

    If you desperately need a modal alert you could craft one yourself using a transparent div with a z index higher than the elements of the user interface that consumes events and then put another div above that with your message.

    I usually can find some other way to get the user the information they need.

  10. I personally had been looking for ideas for
    my personal web site and encountered your
    own blog, “Hybrid Mac applications Teton Technical”, do you mind in the event I actually use some of your own tips?
    Thank you -Edison


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: