With DevMate Closing Shop, Here's What You Can Do

null
Table of Contents
  1. Licensing
  2. Trial periods
  3. Web store and order fulfillment
  4. Updates
  5. Backwards Compatibility
  6. Subscriptions
  7. Conclusion
DevMate service announcement

DevMate are closing their doors. The announcement isn't news anymore, but since I didn't use their service, I didn't think much of it. I did report back in 2016 when they changed their pricing model. Nowadays I discover more and more people struggling to migrate away, and my blog pops up in their searches – apparently because I wrote a book on selling apps on FastSpring.

This post is meant to help you figure some things out, but I don't yet have a compelling alternative to offer. As far as I know, there is no fully compatible drop-in replacement.

You have to tinker a bit. But not that much, and I can help you break down the problem and offer some perspective.

Licensing

This is probably the most interesting problem, because figuring out a licensing scheme is the core of selling outside the Mac App Store.

There are different ways to copy-protect your app to some extent. I stick to offline licensing, where people enter their name and a license code, and this unlocks the app. That't the approach I explain in my book, too.

DevMate instead opted in to online licensing: you enter a serial code, the DevMate server is asked for permission, the app gets its OK, and functionality is unlocked. I would think the app receives an authentication token that's good for a while and perpetually refreshes to keep itself unlocked.

Search the web for "license as a service" and you'll find a couple of software licensing service vendors. I cannot recommend any. I think their pricing model doesn't suit indies like me well; $10 for X active users, how'd that work for your business? Recurring cost for non-recurring income is, in the long term, a liability. I'd prefer a different pricing model. A fixed price per purchase. Am yet looking for this to be offered somewhere. It's not lucrative, I get it, but it's the only sensible way I see for the most common app pricing model out there used by indies.

See also:

  • My short wireframe for server-side licence activation. I haven't implemented this service (yet), but this is how I'd approach writing the rather simple server scripts.
  • Mike Rundle's still useful Licensing State of the Union from 2010, discussing popular licensing options.
  • CocoaFob licence code generator and verification algorithm. Uses DSA private keys on the server to generate license codes, and a public key in your app to decrypt the info. FastSpring supports this out of the box.
  • Tyler Halls's outdated and archived Shine self-hosted web service that did sport payment processing, license code generation, etc. with simple PHP scripts. Could be useful for inspiration event though nothing happened there in the past decade, but some forks are still very active.

Trial periods

You don't need server-side validation to implement trials. Put the trial start and end times somewhere safe, and you're good to go. UserDefaults may not be the safest place for unencrypted dates, but it's a start. Non-programmers will likely not know or want to circumvent this mechanism anyway. You can encrypt the information, or store it in a different place, to make it harder to bypass this limitation.

If you have made it this far and put a macOS app up for sale, this is clearly not a hard problem.

Web store and order fulfillment

Provided you were using DevMate, you already have a FastSpring account. I love FastSpring! You might find FastSpring's backend and store front quite ugly, though. That's because DevMate is so old, you cannot even use the cool new FastSpring features. I am using the Popup Storefronts for all of my app landing pages, because the checkout is so crazy simple, fast, and looks kinda cool. You won't miss any functionality from the old store backend.

So FastSpring sends the invoices, order fulfillment emails, and license details anyway. Maybe you don't look a lot at the FastSpring backend, but they are what really powers your store. This is good news, because the only part of the process that needs replacement is the license generator. It's a proprietary DevMate integration – that will soon be defunct. You can replace this with your own web-based license generator in no time.

See also:

  • My app TableFlip. Click the "Buy" button to see what the Popup Storefront looks like. I think it's kinda neat.
  • My web store where you can buy multiple apps at once, with shopping cart and all.
  • The famous Sketch.app's store page: it uses a custom template and the old FastSpring Store. Looks better than yours? Then you can ask the FastSpring support to help match the style!

Updates

DevMate uses a fork of Sparkle to distribute updates. The upstream version of Sparkle is very good already, and I don't know what stuff they changed that's not part of the public activity of their fork. They seem to have adjusted update signing and supported Sandboxing earlier than the original.

In the end, it's a Cocoa Framework that consumes an RSS feed and downloads updates. I do write my updates feed manually. With my very own, very sore hands! It's not a lot to do, though automating the process sure would be nice. I never bothered, though. That's how painless it really is.

Look at the empty shell of an update feed:

<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:sparkle="http://www.andymatuschak.org/xml-namespaces/sparkle"  xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>YOUR FEED TITLE</title>
    <link>YOUR INFORMATION URL</link>
    <description>YOUR DESCRIPTION</description>
    <language>en</language>

    <item>
      <title>Version 1.2.3 Beta</title>
      <pubDate>2019-08-02 09:37:00 +0100</pubDate>
      <sparkle:minimumSystemVersion>10.11</sparkle:minimumSystemVersion>
      <enclosure 
          url="URL_TO_YOUR_APP" 
          sparkle:version="555_BUILD_NUMBER" 
          sparkle:shortVersionString="1.2.3_VERSION_STRING"
          length="15113206" 
          type="application/octet-stream" 
          sparkle:dsaSignature="SIGNING SCRIPT RESULT" />
      <description><![CDATA[
        HTML INFO HERE
      ]]></description>
    </item>

  </channel>
</rss>

I copy and paste the previous item, adjust the title, date, the attributes in <enclosure>, and then paste a HTML version of the release notes or changelog into the <description>. Done.

If you never added the Sparkle updater to your project before and relied on the DevMate SDK, read my blog posts on the topic to get started.

The new, Sandboxing-compatible approach uses a few XPC helpers. That was very intimidating, I admit. But I documented everything for your convenience in this little series: "How to Migrate to the New Sparkle Updater XPC Branch"

See also:

  • How to migrate updates to your own servers: (Updated 2019-09-13) I blogged about where you can find the existing feed. You should upload a copy to your own servers, then request a redirect of the feed as soon as possible.

Backwards Compatibility

Let's say you have set up your own server endpoint that generates and verifies serial numbers, and figured out where to click in FastSpring's backend to connect them with your server. Time-based trials work, too. Nice. If you start from scratch, all of this shouldn't take longer than 2–5 days, depending on how much experiments you do. I already added a lot of padding, so you might get away with one long day of work, if you're truly the lucky, clever, and sexy person that people always tell me you are.

So what about existing customers?

Get a database dump from FastSpring with all your orders. The order information contains the license code/serial number already. You will need to parse the output and put it into a database on your server, so the server can support existing serial codes. That's all you need: support for existing serial numbers. New purchases can just as well use different serial numbers. If the DevMate format was id123123123123xxx, screw that and use DSA-encrypted UUIDs if you so fancy. Or stick to the very nice CocoaFob like the cool kids.

If you have a copy of your own app installed and activated, peek into its UserDefaults to see if the license code is stored there. If so, use the same key. With your new token-based authentication, you can send the license code to your shiny new server, obtain a token, and unlock the app – the user will not notice a thing if the request is handled quickly. Your approach would be 100% compatible, since the input, the license code, is the same!

Subscriptions

I don't yet know if and how DevMate handled subscription pricing models. Let's assume they did, similar to the Mac App Store.

You can set up the same with FastSpring, too. They have powerful subscription functionality. But they do not manage the state of ongoing subscriptions for you. You will have to write a server script (again) that receives webhooks/notifications by FastSpring on successful billing. You will have to manage the user data in your database, though.

I strongly advise against storing the credit card. That's just too much responsibility.

Your server endpoint and FastSpring need to communicate in a somewhat secure manner. You need to exchange secret tokens, for example. Generate a random string, put it into the FastSpring webhook setup, and check incoming requests if they contain this string in the query parameter list. Since this is server-to-server communication, malicious parties cannot easily observer the traffic after order completion. (As opposed to local app-to-server traffic.) A unique access token aka random string can do wonders. Add a check for the incoming connection, too. FastSpring support will gladly help you with that. If it's not the FastSpring server IP, reject the request. That should make attacks pretty hard already.

Use licensee name or email or the internal FastSpring order ID to identify the customer and associate the payment with this info to figure out how much longer the app should unlock. You can encode this info in the authentication token, too, if you want, to keep the app unlocked until the currently paid-for subscription period is over.

I haven't ever written a server side script to manage subscriptions. I cannot tell you how much work really is involved in all this. I would like to figure this out and empower y'all with detailed knowledge, but alas, today I'm not yet able to.

So subscriptions boil down to:

  1. Recurring payments: completely handled by FastSpring already.
  2. Storing the subscription period on your server, e.g. in a database.
  3. Adding a webhook endpoint so FastSpring can notify you about cancellations and renewals, and securing this endpoint against attacks.
  4. Adjusting the app's license check to take the end of the known subscription period into consideration. You can encode this information into the authentication token that is sent from server to your app during perpetual online activation.

It's more work than the rest, and it's an important piece of infrastructure, but none of these parts are hard to pull of.

See also:

Conclusion

Since I mentioned Sketch.app before: their business model is based on annual renewal of access to udpates, much like subscriptions, but a bit different. Renewal is cheaper than the first year of an initial purchase. You can use the app in its current form for as long as you want. They make the renewal work by looking up your existing license information in their database and then offer a discount or a product variation at a reduced price. Either way, Bohemian Coding, creators of Sparkle, have spent some time over the last couple of years to customize this process. From some email back-and-forth with Pieter Omvlee, I know that they started much simpler, processing payments manually. And they're not alone, according to the data that influenced my book. You're in a very lucky position to start with a powerful e-commerce solution like FastSpring right away. Don't panic.

I think you can be kind of happy that it's DevMate you relied on, and not some other service with a proprietary infrastructure. DevMate was built upon open source frameworks like Sparkle, and integrats with the powerful FastSpring e-commerce backend that is super useful on it's own already. The license-as-a-service providers I had a look at seem far less promising. If they go away, you're screwed. DevMate's sunsetting is just a nuisance once you know what you have to do.

Just last month I have helped a new client put their new app on sale via FastSpring. The overall process didn't take more than 2 days. If you need server-side license activation and subscriptions, you need more time. And I don't have any server side script ready for you to use, yet, so you have to get your own. You can accomplish all of this before DevMate does sunset later this year. That's worth something.

If you figure out something useful, please share! Everyone can use a little help with the transition these days, and I'm happy to link to your server scripts and whatnot!

Browse the blog archive