Kagi Universal
January 11th, 2006Now that Apple has announced the immediate availability of Intel-based Macintoshes, the developer community needs to get serious about adjusting our projects so that they build and run natively on the machines.
For a long time, Apple has made available the required SDK for “dry running” our projects as Intel-compatible builds. Some developers even took Apple up on the “transition kit” systems, which put Intel machines (though quite unlike the shipping units) in the hands of developers from a very early stage.
A common thread on the mailing lists seems to be the unhappy scenario of essentially having ones own code ported and ready to test, but being held hostage by the slowness of another library upon which you depend. When the library is open source, it’s easy enough to take responsibility for it yourself. Get your feet dirty and port the dang CurlHandle class over yourself! But many of us (perhaps unwisely) have gotten ourselves into situations where we depend upon the compiled code of others in our shipping products.
Kagi’s KRM module allows Kagi vendors to present users with an integrated purchasing dialog. It’s essentially a single dialog that takes the user’s financial information and ships it off to a Kagi server for further processing.
For those of us who have been using the Cocoa-specific version of KRM, the wait has been long for a universal version of the libraries. In fact, the wait will be very long. It doesn’t appear that Kagi is planning any further updates to the Cocoa-specific module. Instead, we’re offered the “Zonic KRM” module, which is a straight-C CarbonEvent based solution.
At first, I was annoyed by the presumption that Cocoa developers should have to pull up roots and switch to a new library with a new API (a straight-C one, to boot!). But after downloading and using the Zonic KRM solution, I am happy to report that it’s an overall cleaner and easier to use module than the previous Cocoa-based framework. As a single library archive and associated header file, this requires none of the linking and packaging headaches of the Cocoa KRM package. The API is straightforward and offers few opportunities for careless error. Even the UI is, ironically enough, improved over the Cocoa version.
The only major snag I’ve run into is that the Zonic purchase window doesn’t appear in the floating layer as the old Cocoa KRM did, and seems to suffer some activation issues when invoked from my LSUIElement application. These types of problems were what originally led me to choose Kagi over eSellerate, whose Carbon-based solution had the same problems. Hopefully these can be resolved with Kagi – I’ll have to investigate. [Ed. Note: These issues were more or less mistaken impressions, and are somewhat elaborated upon in updates at the end of this article]
All the improvements will mean little, however, to Carbophobic developers who have grown accustomed to avoiding most APIs that don’t fall firmly into the Cocoa space. I don’t blame them. If I didn’t already know this Carbon stuff, I probably wouldn’t want to sidetrack my rapidly progressing project to figure it out, either.
In the spirit of helping these developers out, and with the somewhat selfish goal of encouraging as many Intel-native apps as possible by the time my MacBook arrives, I’m posting a very simple demo project that shows how you might integrate the Zonic KRM modules into a Cocoa application. For this example, I’ve taken the attitude that you want your exposure to Carbon to be brief, handing back control to a “sane, Cocoa world” as soon as possible. The gist is pretty simple:
- User pushes a button, invoking an IBAction method.
- Action method installs a Carbon event handler for Zonic “I’m Done.”
- Action starts a modeless Zonic registration dialog.
- Zonic finishes and issues the Carbon Event.
- Callback receives event and passes event-completion structure back to Cocoa.
[Ed. Note: It has been pointed out that using the “modal” Zonic dialog is exceedingly simple, and doesn’t require any use of the Carbon event API.]
Note that since I’m not sure I have the right to redistribute the Zonic library and header file as-is, I’m not including them in the sample project. You’ll have to download them directly from Kagi.
I hope this proves helpful to some of you.
Update – My LSUIElement problems seem to be worked around by using the modal version of the Zonic dialog API.
Update 2 – Wed, 1/11/2006, 1:40PM EST. I’ve updated the sample project to include demo cases for both Modal and Modeless variants of the Zonic KRM dialog.
Update 3 – Wed, 1/11/2006, 1:55PM EST. Another update to the sample – should dispose of the Zonic result structure when done with it. Also, it should be noted that the “LSUIElement” related problems alluded to above are more general. It appears that Zonic KRM’s modeless dialog is not well suited to being displayed while a Cocoa NSPanel of any kind is being displayed.
Update 4 – Thursday, 1/12/2006, 1:55PM EST. Incorporate memory leak fix suggested by Kirk in the comments.
Update 5 – Friday, 1/13/2006, 10:48AM EST. Friday the 13th Special! Kagi and Zonic have kindly agreed to let me include the Zonic library and header file in the demo project, so it should be buildable as soon as you download it, presuming you have Xcode 2.2 installed.
Update 6 – Tuesday, 2/21/2006. I meant to point this out earlier, but forgot. There is a problem in the 1.0.4 Zonic release that causes it to crash on 10.2 deployments. An ingenious workaround was discovered by another Mac developer and shared with me via Kagi. Simply lipo the PowerPC code from Zonic 1.0.3 with the Intel code from 1.0.4. I’m using this solution in the interim and it gives a solid fix to the problem the Zonic 1.0.5 release is ready.
January 11th, 2006 at 1:08 pm
I recently added the Kagi KRM to my app, then noticed down at the bottom of the page that it would not support universal binaries. Cursing them for not having this warning a little more prominent I went and changed to the Zonic KRM. The Zonic example and linkage as a static library is so much clearer and cleaner than the Kagi KRM. I just used the Zonic modal case example as-is in my Cocoa app and it works nicely.
The modeless example is nice, thanks. I thought I had given up on old MacOS API’s when I got a NeXT cube over a decade ago but I guess it is around forever to haunt me, or something.
January 11th, 2006 at 1:27 pm
My experience was similar. I was reluctant to go to Zonic, but I have a Carbon background, so it wasn’t too painful. I, too, have found the modal to be the best idea, and it certainly is faster. The old “Cocoa” version (which I found out was Java-based) was so long in coming up that I felt I had to put up a wait for it window with an indeterminate progress indicator. That’s gone now. I put the Zonic KRM into my app last night, and it took about an hour, most of it my own problem.
January 11th, 2006 at 4:24 pm
Folks;
I’m in the same boat as original post. Soon to ship Cocoa app but I’m not a CarbonBrain.
I looked at the Zonic and well ugghhh!
Big UPs to Daniel for the demo he posted!
Kagi told me today that Zonic would release 1.0.5 in ~ 2 weeks which would feature a ‘Cocoa wrapper’…
No further details as yet.
I’m hoping the weight of us Cocoa-Only folks helps Zonic to realize a simple Cocoa demo (even it it uses the C lib) would be a huge benefit!
Steve
January 11th, 2006 at 4:48 pm
If you’re not familiar with registering Carbon Event handlers, the best approach is just to use the modal dialog.
That is how most apps invoke our KRM at present, and reduces things down to literally a couple of lines (configure, invoke, and dispose). Hook that up to a button or a menu item, and you’re done.
We do plan to add some Obj-C support, and this will primarily be to simplify the modeless case (by receiving the Carbon Event and forwarding it on to a selector).
Regarding windows, there have been a couple of situations in the past where Cocoa’s window layering was incorrect and the focus could be mis-set for particular Carbon window types. Most of these were cleared up in 10.3, but if you have a reproducible fail case let us know and we’ll investigate.
January 11th, 2006 at 5:10 pm
Hi Dair – thanks for taking time to respond here. I am looking forward to an official Cocoa wrapper. Hopefully this example will help people out who want or need to get something out ASAP in the next couple weeks.
I can’t tell by your comments about the layering issues if you think the modeless/NSPanel conflicts should be resolved. If you want to reproduce a simple case just download my test project linked in the above entry, open the NIB file and change the Cocoa class of the main window from NSWindow to NSPanel. Build and run the app, and you should find that after clicking the “Buy Modeless” button, you can’t actually type anything in the credit card text. If for some reason this does work, try clicking back to the main window and then back to the Kagi dialog.
January 12th, 2006 at 10:21 am
Cool and useful example. Thanks! I’m considering integrating sales stuff into a couple of apps, but one of my major quibbles with the situation is that I don’t like being beholden to third-party SDKs (especially ones that ship binary-only!).
January 12th, 2006 at 10:27 am
Yep, I agree David. I very much consider Kagi a valuable resource for “bootstrapping,” but would probably look towards a custom or source-licensed solution as sales increased. It’s not only more under your control at that point, but you’re in a position to collect higher returns on purchases.
January 12th, 2006 at 10:50 am
The final Universal Binary OS release came out from Apple on Tuesday 11am Pacific.
On Wednesday, Zonic and Kagi released a Carbon Universal Binary that is fairly easy to incorporate into a Cocoa app. It doesn’t yet have the Objective-C wrapper, but that is coming.
The latest details are always posted at: http://www.kagi.com/KRM/zonickrm/index.html
That web page currently (Jan 12th) states: “Note for Universal Binary Cocoa users: Version 1.0.5 of the ZonicKRM, which will be released in a couple of weeks, will include an Objective-C wrapper for “Cocoa support”. However, C API is callable from Cocoa apps as well, and so 1.0.4 can be used as-is with Cocoa.”
We both felt it was more important to release a production UB version as soon as possible than to delay the UB release to wait for the Cocoa wrapper.
January 12th, 2006 at 10:57 am
Thanks, Kee. I strongly agree with your decision to release a universal build now as opposed to later. In case the context for this post isn’t clear, it was in response to some sentiment among developers that it would be difficult to integrate the Zonic KRM into a Cocoa application. Clearly, the Zonic folks have done a superb job at making this easy, and my easy demo here is only meant to prove that.
January 12th, 2006 at 11:20 am
It appears that if the user cancels or there is any sort of error, that the ZKRMResult never gets DisposeKRMResult() called on it.
Is this a leak?
January 12th, 2006 at 11:54 am
Good catch, Kirk. I think you’re right. The “zonicKRMCompleted:” method shouldn’t be disposing of the result, since the modeless code path disposes of it after calling the callback. I’ve taken the dispose out of the callback and added a dispose in the modal case immediately after calling the callback.
January 16th, 2006 at 10:19 pm
I had been waiting for the universal binary Cocoa KRM for some time, and was going to continue to wait for the Cocoa wrapped Zonic KRM, because the thought of having to go back to Carbon gave me chills, but your post convinced me. Thanks so much. It took me less than two hours and now I have a universal binary application.
March 12th, 2006 at 4:28 am
I still have problems with Zonic 1.0.4 on 10.2 deployments (the application crashes when I try to launch Zonic 1.0.4 on 10.2 system).
Can you publish the “hacked” version of Zonic 1.0.4 library as you described in “Update 6”?
March 12th, 2006 at 8:59 am
Gregory: I’m not comfortable with the licensing implications of posting such a hack, but the gist of what you want to do is something like this. I’m changing the names from “libZonicKRM.a” to names that indicate the version the binary came from. Let’s assume you have a copy from 1.0.4 and a copy from 1.0.3 in the same directory:
# get single-architecture copies of libZonicKRM.a lined up:
cp libZonicKRM-1.0.3.a libZonicPPC.a
lipo -remove ppc libZonicKRM-1.0.4.a -output libZonic386.a
# merge them into a single universal binary “libZonicKRM.a”
lipo -create libZonic386.a libZonicPPC.a -output libZonicKRM.a
Hope this helps.
March 18th, 2006 at 8:04 pm
Sorry guys, but what happened to ZonicKRM update? Sadly it’s still 1.0.4 version.
March 28th, 2006 at 4:21 pm
[…] The 1.0.5 release of Zonic’s KRM library for Kagi has been released. I don’t have time to look carefully at this now but for those of you who were following my advice about porting your Kagi KRM app to Universal, this release includes built-in Cocoa support. Link. […]