In early 2022, a client approached Woodridge with a request to develop a large-scale enterprise app built to last for years. Given the scope of the project, we decided to take on the challenge of building the app using SwiftUI.
As the architect of our iOS team at Woodridge, I was tasked with planning the app’s architecture. However, adopting SwiftUI for such an extensive project presented a unique challenge due to the lack of well-established architectural best practices. My journey to choosing (and eventually inventing) a design pattern occurred in three phases.
As an experienced UIKit developer, my first inclination was to choose an architectural pattern that worked well in the UIKit world. This proved to be problematic, the reasoning for which is best expressed after a brief history lesson.
When Apple released the iPhone SDK in 2008, the recommended design pattern to build around your UIKit application was MVC (Model-View-Controller). From a high level, this pattern involves your data model, your view, and a controller that ties them together (although in UIKit your view and controller are combined into a single “view controller”). Once the complexity of applications grew beyond the basics, this pattern often resulted in a familiar problem: massive view controllers.
Massive view controllers came about for a myriad of reasons. For instance, it’s incredibly hard to use view composition (breaking down a larger view into smaller subviews) within UIKit, so most developers give up and just create a single view controller per entire screen of an app, bloating each view controller. In addition, most view controllers end up containing common functionality like networking, further adding to the bloat. State management (one of the most important aspects of a mobile application) was also tricky – storage and management of application state was largely left up to the developer, so all of it ended up in the view controller by default.
All in all, the problem came down to view controllers having too much responsibility. In order to mitigate this issue, developers used a myriad of additional design patterns that were meant to solve the problem of massive view controllers by separating the concerns normally held by view controllers into separate components:
In 2019, Apple introduced a new UI framework, SwiftUI. SwiftUI is very different from UIKit. Where UIKit is imperative, SwiftUI is declarative; rather than the developer dealing with views directly, they specify how the UI should look and the framework handles the rest. Rather than developers handling state management themselves, SwiftUI has built in state management and handles view updates upon state changes automatically. Where view composition is difficult in UIKit, it’s the default in SwiftUI.
As you can see, SwiftUI is not just a new UI framework; it’s so different from UIKit that it completely changes the game we’re playing. Most of the circumstances that created the massive view controller problem in UIKit don’t exist in the world of SwiftUI, which means that we don’t need to use design patterns that were specifically designed to solve this problem.
So even though choosing a UIKit-friendly design pattern seems to make sense at first glance, one quickly realizes that these patterns would be solving nonexistent problems in the world of SwiftUI. Not only that, but some of these patterns (like VIPER), might actively discourage developers from writing good SwiftUI code. Patterns like VIPER create significant boilerplate on a per-view basis, which discourages developers from splitting up views into smaller chunks since each view adds so much code and complexity. Michael Long has written about this extensively.
All in all, design patterns should be solving problems rather than potentially creating them. UIKit friendly architectures were conceived of to solve the massive view controller problem, which is no longer present in SwiftUI.
Okay, so applying my UIKit knowledge to this problem isn’t going to solve it. I then scoured the web and found that most people recommend MVVM as the standard SwiftUI design pattern.
As discussed above, MVVM dictates that each view gets its own ViewModel component that will contain its state and business logic, and the ViewModel will bind its state directly to its view. This sounds like a great candidate for the state-driven, binding-based structure of SwiftUI, and we can achieve it easily using ObservableObject (as well as the new @Observed macro).
There are pros and cons to this approach, the pros being that MVVM separates our business logic from the view, making it portable and easy to test. However, the cons of using MVVM with SwiftUI are vast and in my opinion, outweigh the pros:
Given the drawbacks when applied to SwiftUI, I feel that MVVM is not the right tool for the job. The pattern effectively separates view and business logic but puts up a plethora of roadblocks between developers and core SwiftUI features in the process. I think we can come up with something better suited for the world of SwiftUI. It also looks like I’m not alone in this opinion.
So now what? The wonderful (and terrifying) thing about using a fairly new framework like SwiftUI is that best practices haven’t yet been established. The more you look for others who have plowed the path for you, the more you realize that you’re one of the plows. With this in mind, I realized that we’ll need to chart our own course, that we’ll need to come up with our own architectural pattern from scratch.
Taking a step back: what is the point of software architecture, anyway? I guess we’re just supposed to do it, right? To please the architectural gods?
I beg to differ. My philosophy on architecture is that it should have purpose: it should solve problems. By its nature, SwiftUI has solved the problems that created massive view controllers; this is exciting because it means that we can focus our efforts on solving other, more general architectural problems, and the resulting architecture could be more simple and elegant than UIKit focused architectures of the past.
So then, what problems are we trying to solve with more general architecture? Typically we’re trying to prevent spaghetti code; we want to end up with a structure to our code that is easy to understand and is easy to scale. Generally, we are shooting for maintainable code. Here are the general principles I chose for this new architectural pattern:
With these requirements in mind, I conceived a design pattern that I call MVSU. The pattern has strong roots in MVC, domain-driven design, and Clean architecture, but it has unique properties that I think make it an especially good fit for SwiftUI. The pattern is made up of 4 groups of components:
I’ll go into more detail on each type of component:
In some apps, common tasks like networking, displaying alerts, handling errors, etc can end up being strewn and repeated throughout the codebase (or it ends up in your mediation layers like viewmodels). MVSU specifically dictates that we move these types of repeated tasks into classes with the suffix “utility” (e.g. NetworkUtility, SessionUtility, LoggingUtility, etc).
In adhering to the single responsibility principle, these utilities should be highly focused – they should only perform one type of task or a few highly related tasks. Services then utilize utilities to perform their higher-level functions. By moving tasks like this into utilities, we keep the codebase DRY (don’t repeat yourself) and we allow services to focus only on what is unique to their domain. The rule of thumb here is that if multiple services are performing the same logic, it probably needs to be moved to a utility.
class NetworkUtility {
func perform<ResultType: Decodable>(request: Request<ResultType>) async throws -> ResultType {
// ...
}
}
class LogUtility {
func log(type: LogType, description: String) {
// ...
}
}
class FileUtility {
func save(data: Data, toFileUrl fileUrl: URL) throws {
// ...
}
func retrieveData(fromFileUrl fileUrl: URL) throws -> Data {
// ...
}
}
Many patterns like MVC, MVP, MVVM, and VIPER separate business logic by view (i.e. each view has its own separate controller, viewmodel, etc). In MVSU, we separate our business logic by domain – this means that each type of data that your app consumes gets its own service (e.g. for a donut shop, this might look like DonutService, OrderService, UserService, etc).
Separating business logic by domain has a few advantages:
Another thing to note about services is that they’re stateless – state should be stored in views, not services. More details about this in the Views section.
// Note that dependency injection strategy is up to you, but I recommend using a library like Factory (https://github.com/hmlongco/Factory), which is the strategy employed below
import Factory
class OrderService {
@Injected(\.networkUtility) private var networkUtility
@Injected(\.logUtility) private var logUtility
func createOrder(items: [ItemModel]) async throws -> OrderModel {
do {
let response = try networkUtility.perform(request: .createOrder(items: items))
return OrderModel(record: response.order)
} catch {
logUtility.log(type: .error, description: "Order error occurred: \(error.localizedDescription)")
throw RuntimeError("Unable to create order")
}
}
}
As mentioned, MVSU encourages developers to use view composition and split up large views into smaller views, keeping each view lean and narrowly focused and avoiding the massive view controller problem of the past.
In MVSU, services are stateless – instead, views maintain all of their necessary state. This is for a few reasons:
struct OrderView: View {
@Injected(\.orderService) private var orderService
@Injected(\.paymentService) private var paymentService
let availableItems: [ItemModel]
@State private var itemsInCart: [ItemModel]
@State private var orderAwaitingPayment: OrderModel?
@State private var error: Error?
var body: some View {
VStack {
ForEach(availableItems) { availableItem in
AddItemToCartButton(availableItem) { item in
itemsInCart.append(item)
}
}
Divider()
// I Highly recommend creating an AsyncButton view: https://www.swiftbysundell.com/articles/building-an-async-swiftui-button/
AsyncButton("Create Order") {
do {
orderAwaitingPayment = await orderService.createOrder(items: itemsInCart)
} catch let orderError {
error = orderError
}
}
}
.sheet(item: $orderAwaitingPayment) { order in
PaymentInfoView(order: order)
PaymentButton() {
await paymentService.createPayment(forOrder: order)
orderAwaitingPayment = nil
}
}
.errorAlert(error)
}
}
This is the least unique part of the pattern. Your model involves your data types and any persistence layer needed (e.g. Core Data, SwiftData, Realm, etc). Note that maintaining SwiftUI’s feature set is paramount in MVSU, so views should be allowed to communicate with the model directly through SwiftUI’s property wrappers like @FetchRequest or @Query.
In my opinion, the introduction of SwiftUI has been the most significant transformation ever in the realm of iOS development. SwiftUI is not just a new UI framework – it’s so different from UIKit that I think it begs us to rethink the entire way we build apps. It might be time for all of the iOS community to take a step back and think about why we make the architectural decisions we do in the first place.
My journey to choosing, and eventually creating, a design pattern made me realize why we were using common UIKit design patterns in the first place. In my opinion, UIKit isn’t well suited for the level of complexity reached by most apps nowadays, which created problems that we needed to solve with specifically designed architectural patterns. SwiftUI doesn’t have those same problems, so there’s no need for their solutions.
This new landscape is both terrifying and exciting. This inevitably means that some of the knowledge and skills that we’ve been honing in the UIKit world need not apply. It also means that we get to chart our own course, and maybe we’ll never again have to deal with some of the worst parts of UIKit development. I for one am excited to continue this journey through uncharted waters.
Native vs Hybrid apps are two different ways of writing your mobile application. Woodridge may use either depending on the type of your application, your risk tolerance of depending on a framework, and how much native functionality you need.
Native apps use frameworks and tools that are local to the platform. Going with a native-first approach would mean writing two separate apps, one for Android and another for iOS. On Android, you would write the app in Java or Kotlin. All of the layout would be done in the Layout Editor in Android Studio. On iOS, everything is done in XCode, with the code written in Objective-C or Swift and the layout done in XCode Storyboards.
Hybrids apps use a variety of techniques that allow you to write your application with a single codebase. That code is then compiled to the respective native platform. The end results of a hybrid compilation process are projects that can be used in Android Studio or XCode. The downside is that you cannot make changes in these projects without the results being overwritten the next time you compile.
In general, the more native features you plan on using (camera, GPS, Bluetooth), the more it makes sense to use a native app since these features are platform specific. The sensor APIs are very different between iOS and Android, which means that code reuse that would not be possible.
(via https://www.topsinfosolutions.com/blog/hybrid-app-vs-native-app-debate/)
Hybrid apps work by embedding a web view (typically a WebView in Android or a WKWebView in iOS) and then sending information back and forth between a Javascript bridge. Any information that you want to send between the web view and the native side is done through message passing. This adds a layer of complexity and a mismatch between the objects inside and outside the webview, which can only indirectly communicate.
If you use a hybrid app, your app will look the same on all devices, but it will not match the feel of the other apps. For example, a list view will not look like a default list in iOS, and you will not get the native features like pull to refresh or sticky headers by default. The native components, which are performant and have already been proven from a usability perspective, will not be able to be used inside of a web view. This includes the native maps component, scrolling list views, and camera previews.
(via https://blog.mobiscroll.com/js-vs-native-controls-in-web-and-hybrid-apps/)
Certain types of information work better in a web view than in a native container. For example, anything document or text related is shown better in a web view. The web has always been a medium for displaying documents and only recently has grown into a format for web applications with the evolution of Javascript and HTML5.
Hybrid apps used to be slower, but the web views on both Android and iOS have improved and also techniques such as CSS-driven animations and transitions can perform reasonably well on newer phones. On older devices, native transitions would remain the best choice.
When choosing a native vs a hybrid approach, you also have to consider the cost of maintaining two separate apps versus maintaining a single hybrid app. The more native functionality you need, the more overhead that will be needed to get the hybrid app to work properly.
The development environments of XCode and Android Studio are great for rapid application development. Since the mobile world has converged on two operating systems (iOS and Android), there are only two platforms you need to support by going native, versus the 4-5 in the past. This means that by going native there is much less to support than if there were more platforms.
Cordova is a popular choice for writing hybrid apps. Given some Javascript and HTML, Cordova generates an app for each platform which consists of a single web view. You write the app in HTML and Javascript, which gets loaded in the view. Then, there is a Javascript bridge and an interface that you can write plugins for. One downside is that the plugin ecosystem is active and many of the plugins you use have deprecated APIs that are not maintained. Any platform-specific functionality will have to be done through a plugin, including splash screens and native alerts.
React Native is different than Cordova, in that it dynamically creates native components orchestrated by Javascript. There are only a certain number of cross-platform native components implemented, but it gives you a native look. One of the downsides is that although you are using native components, you have very little control over the specifics of what is going on. This is due to the fact that you are writing code that gets compiled to native, not the native code itself. It then becomes more expensive and time-consuming to fix any bugs, although it might have been a quick fix with direct access to the native code.
Instead of implementing the whole app natively, you can use web views to show a specific page. For example, you might want to have a screen where a user can view his or her profile information. This page could be loaded from a server dynamically, meaning the page could get updated without the user having to reinstall the app. One of the downsides of having many separate web views is that the startup time is around ~1s even for a sparse page, so the user will have to wait for the information to be loaded.
One of the main pain points of hybrid apps is that it is difficult to “jump out” of the embedded web view or framework to a native view. For example, if you make a single screen native, then it would involve a large restructure to the whole app, since the hybrid app framework assumes your app is only structured a single way. Going native-first is the opposite. It is very easy to make a single page a web view and the rest of that app native.
In general, there is not a clear answer to what is the best approach to mobile app development. Our recommended approach will vary from project to project. Hybrid apps can be a good choice if you want to get a simple, MVP of your app to market as quickly as possible with minimum features. However, native apps will offer the best performance, user experience, and security. We recommend native applications to all of our clients if their budget allows for it. However, hybrid app development can be a cost-efficient way of getting a simple application to market quickly.
At Woodridge, we work with a variety of codebases. These codebases consist of code we have written as well as codebases that we have inherited. We have inherited code from developers that retired or passed away and code from other developers where the code is less friendly to work with. Many of our prospective clients end their current relationship because the app development firm does not deliver on their promise. Specifically, it is the quality of work, lack of knowledge and the lack of best practices by other Android developers. Recently, we inherited several Android apps because other Android developers could not meet the client’s technical needs. These Android apps are extremely complex, require special skill sets or, at a bare minimum, require a great degree of developer ingenuity and resourcefulness. Below are some of the best practices for Android developers to keep in mind while working on new and existing projects. This is not an all-encompassing list, but it is a great place to start.
Use packages! Using packages is one of the best ways to keep your code organized. This helps keep related segments of code logically grouped together and easy to find. For example, group all of your activities together in an activity package. In most cases, you will want to name members of that package in a way that indicates what the package is apart of (e.g. SplashActivity, LoginActivity, SettingsFragment, etc). If done properly, this can minimize the number of public methods and variables you have in your files by allowing you to use package-private methods and variables as an alternative.
All user-facing strings belong in the strings.xml file. This makes adding additional languages, like Spanish, to your app easy. Text changes can also be made quick and easy. Colors should also be stored in the appropriate resource file, namely colors.xml.
Layout files should use the strings and colors from the appropriate resource files and should be named appropriately (e.g. activity_splash.xml, fragment_settings.xml, view_user.xml, etc). They can also be used if you have the same view element in multiple spots like a reusable list item.
Android runs on a variety of devices with a variety of screen qualities. In order to ensure your Android app has a smooth look and feel across all phones and tablets, image resources must be provided for all screen densities (mdpi, hdpi, xhdpi, xxhdpi, and xxxhdpi). It is not recommended to copy and paste images from an iOS project into an Android project and vice versa. Separate images should be created for both platforms since iOS and Android apps differ.
Styles are a great way to reuse the style of different User Interface (UI) elements across the project. For example, when you have multiple buttons across a variety of pages that look the same, you can place the single style in the styles.xml file and then all of your buttons can share that style. If you need to make any changes later then you only need to make it in one place.
Removing unused code should be common sense but surprisingly many Android developers write code that goes unused. If it is unused then delete it. Furthermore, removing unused code makes Android apps smaller and the codebase less confusing. Android Studio even provides a mechanism to remove unused resources such as layout files and strings.
Use well-known dependencies to speed up development so you don’t have to reinvent the wheel every time. Never get stuck with a library that hasn’t seen updates in years. If you do, there is a chance your project will break with future operating system updates. One example of a well-supported Android library is OkHttp which makes HTTP requests easy to integrate into any Android project.
Android Studio is a very powerful Integrated Development Environment (IDE) and it gives some very useful hints so listen to them! Moreover, Android Studio will tell you useful tidbits of information such as your hardcoded string should use a string resource or your public variable should actually be declared as private.
Finally, there are many other things Android developers can do to make their Android app maintainable but this is a great place to start. Above are some of the things that the Woodridge development team keeps an eye out for when performing code reviews on existing codebases of prospective clients. More often than not, we see other developers taking the lazy way out or simply put, they don’t know any better.
We see many items receive a failing grade in the code review which requires a “cleanup phase” when we inherit the project. A little organization and following best practices goes a long way. On a closing note, someone once said, “Always code as if the person who ends up maintaining your code is a violent psychopath who knows where you live.”
Lorenzo Gallegos is a senior developer at Woodridge Software, a custom software development firm located near Denver, Colorado. Woodridge specializes in Web, Android, and iOS development and works with a variety of clients ranging from startups to Fortune 500 companies.
iOS 11 was recently released and that means two things: One, your iPhone just got some very cool new features and two, your apps might break.
At Woodridge, we build web and mobile applications and many of our projects actually include both. Web apps run in browsers which, for the most part, are backward compatible. This means a web app written in 1999 likely will run fine on your 2017 Firefox browser (probably just as well as it did on your Netscape browser).
Mobile apps, however, rely on the operating system of the mobile device. Android and Apple (iOS) are updating their mobile operating systems at a frantic pace. This is great for the user, as better features mean a better user experience. But, if you own an app, it also means that each update has the potential to break your app. Substantial updates, like iOS 11, are more likely to do so.
Fortunately, if Woodridge has been performing regular updates on your app, the changes needed to work with iOS 11 are minimal or nothing at all. However, if it has been 6 months or more since the last update to your software, it might take 3 to 4 days of work to update everything.
We’re here to help. So let’s enjoy these new features, but be ready to keep your apps running smooth. You may want to integrate some of these new features into your app to enhance the experience of your users. With iOS 11, the Files App will be a big one, as will Instant Markup. Let us know if you’d like to chat about how these and other updates that could improve your app.
Kaj Gronholm is the CEO at Woodridge Software, a custom software development firm located near Denver, Colorado. Woodridge specializes in Web, Android, and iOS development and works with a variety of clients ranging from startups to Fortune 500 companies.
Have you considered building a mobile app, or perhaps you have the beginnings of a great idea? Regardless, you’ll have an important decision to make, “Should my app development team build a native or hybrid app?” There are several variables to consider: the initial app launch time, the budget for the app, the app’s complexity, and post Minimum Viable Product (MVP) desires. The answer to this question varies from client to client and in most use cases we will recommend native app development. However, there has been a lot of hype in the mobile development community surrounding a new Hybrid option: React Native.
There are many hybrid options that use frameworks. These frameworks allow you to develop an application with one set of code and export the code to develop software on both platforms, iOS and Android. Some of the most popular hybrid frameworks are: PhoneGap, Cordova, and React Native.
One of Facebook’s open source libraries is called React. React first came out in 2013 as a way to build user interfaces for the web directly using JavaScript. It’s like any other library that comes with a good amount of ramp-up time but it is backed by a passionate web development community that is steadily growing. Though we have not used React in production here at Woodridge, we understand that React offers a clean component-based style to user interface (UI) development formed around the idea that the user interface should reactively update when data is changed. But make no mistake, React and React Native are completely different libraries.
In March 2015, React Native was open sourced by Facebook. React Native builds off React, bringing similar concepts and structure to mobile UI development, and actually carries over a bit of web development ideas to the mobile scene. In fact, when building a React Native app, you won’t be programming in Swift, Objective C, or Java, you will be programming in JavaScript.
React Native is in the same category of other hybrid frameworks such as PhoneGap or Cordova, though React Native greatly differs in its technology. We have developed several mobile apps in the past using Cordova and the general consensus among the team has been a yearning to employ native development. React Native is technologically different than Cordova and in fact is a technology that we’re very excited for. Simply put, React Native is Facebook’s open source solution for building Hybrid mobile apps with a clean Native UI.
The most obvious benefit of using React Native is that it saves money by building both apps simultaneously. You could develop an app once in React Native and deploy it on both iOS and Android. The underlying framework doesn’t distinguish between the two platforms. This is quite promising because native iOS and Android development have very different approaches and it can get expensive. For instance, building a mobile app on both platforms nearly doubles the cost.
The languages needed in each case are also different: iOS uses Objective-C and/or Swift whereas Android uses Java. Finally, all the underlying API’s are different – the way you use the GPS is different, the way to create animations is different, the way you interact with Bluetooth is different. React Native largely gives one code base for both platforms and that certainly is a big benefit.
However, the big caveat is when apps become more complex you end up writing a good bit of native code on top of the hybrid code plus you need plugins for the camera, Bluetooth, and any other item. As the app gets bigger, it’s no longer just one code base, but rather four code bases: the React Native code, the iOS native code, Android native code, and the plug-ins.
In many cases, React Native will bring your apps to market faster on both operating systems than native development because only one code base will need to be written. Less overall work means that React Native could potentially save you some bucks if your app fits the simpler profile needed for a hybrid app. Once you introduce more complex functionalities (e.g. GPS, video recording, etc.), you may want to consider native app development.
PhoneGap and Cordova create single-page applications that run inside of the mobile web browser. So really you‘re running web technologies (HTML5, CSS3, JS) to power your user interface. When using a framework like Cordova, your app will not look like it was built for your mobile device platform. On the other hand, React Native has access to native controls and interaction right out of the box. Components such as Text, Button and Slider will map to its native counterpart. Facebook calls React Native a, “Real native app,” in the context that you really are interfacing with the given platform instead of wrapping around it like Cordova and PhoneGap.
Since other hybrid frameworks are bound by WebViews, they are also bound by the limitations of a WebView. Since JavaScript is single threaded, Cordova and PhoneGap have the potential to lead to sluggish pages on busy screens. On the other hand, React Native makes use of multiple threads and renders UI elements on its own thread. In React Native, JavaScript is not the Atlas of your app.
The largest disadvantage is reliability in complex applications. This is why we recommend that our clients choose native when they were choosing between hybrid and native app development. We have experienced turbulence in some of our apps using Cordova that really had too much native functionality (e.g. GPS, Camera, Bluetooth, etc). Since React Native is relatively new (about 2 years old), we haven’t used it in production. Unfortunately, we just don’t really know how reliable its interface is with more complex native functionality. Native apps can be trusted to be reliable for this kind of functionality.
The longevity of a React Native app may be in question. Facebook previously offered a development platform called Parse. Many applications were fully dependent on this service yet the service was terminated after Facebook-owned it for a couple of years and decided to shut it down. There’s no indication that the same thing would happen with React Native, but Facebook’s long term support of this project is not guaranteed. Google and Apple will always be updating and progressing their interfaces for the lifetime of Android and iOS smartphones.
For clients that may be considering patenting a product that makes use of React Native, more research would need to be done on the current licensing agreement to determine whether or not your license to use React Native could be terminated without warning.
Overall, I was impressed with React Native. I built a demo app to showcase its potential and presented two different designs for the iOS and Android versions that shared almost 80% of the code. My experience with ReactJS definitely helped with learning React Native.
The development team at Woodridge is still skeptical of this framework. Clearly, there are advantages and disadvantages of using React Native but overall the challenges of a hybrid app still exist. We still recommend native app development to our clients in most cases but we will consider React Native when the complexity is very low, the budget is tight and platform calls for the possibility of a hybrid app. Ultimately, a good candidate for React Native would be an app with minimal Back-End or Application Programming Interface (API) work and that doesn’t use the camera, GPS, or Bluetooth.
Tyler Bank is a software developer at Woodridge Software, a custom software development firm located near Denver, Colorado. Woodridge specializes in Web, Android, and iOS development and works with a variety of clients ranging from startups to Fortune 500 companies.
You’ve built an app and now you want to monetize it. It seems like a simple concept – companies sell apps all the time. However, actually collecting payment from your customers into your bank account means making some compromises because there’s no perfect, simple method to do this that fits every use case.
In this blog, I’m not trying to address how to price your app. What you actually charge will have some impact on the app payment method; however, sometimes the way you sell it will also influence what you charge. This blog also isn’t focused on how to set up e-commerce sites that sell products. The focus of this blog is addressing the nitty-gritty of different methods for collecting payments themselves.
Too often the decision on how to collect payment is left for after the app is developed. However, as we shall see, waiting until the end will change the options you have. The goal for this post is not to give all the detail on every option, but just to discuss the high-level pluses and minuses of each choice. Hopefully, this blog will give you a foundation of knowledge so you and your development team can make the best decision.
In this blog, I’ll cover six methods to get money from your customer’s bank accounts into yours and I’ll address how they work for both Web and Mobile Apps. I’ll start with the mobile options, then discuss options that work for both mobile and web, and finally just web options.
One of the simplest methods to collect payment for your mobile app is to charge to download it from the app stores. You put your mobile app in the store and choose a price ($1.99 to $4.99 is the most common, but it can be anything you want). 30 to 60 days after the end of each month, Apple or Google will send you a check. However, you might be surprised to find out the check is for 70% of what was sold, the other 30% stays with Apple or Google.
Why would anyone give up 30%? Well, for one, it is the simplest way to collect payment for your app. Apple handles all payment processing and returns. You have a low-security risk since you never process a credit card transaction. Another reason may be that it’s the only option you have. If your app doesn’t have user accounts or other features that require a back-end server, there may be no way for a user to send you payment.
Selling direct in the app store is also a good option if the price of your app is very low, say under $10. In this case, your goal is volume. It’s much easier for someone to just download an app and click approve payment. At a price point of $1.99, most users are not going to want to go to your website and create an account and enter a credit card. Apple has recently changed its terms if your app is subscription based. Now you’ll pay 30% on the first download, but when the customer renews the second year they will only take 15%. How nice of them.
There are definitely good reasons to sell your app using a per download fee in the App stores and many apps make their owners very good money in the stores; however if your app will create user accounts, and requires a backend server, you may find that there is more money to be made using “in-app purchases” or registration on your website.
This is a corollary to the method above. It’s also known as a Freemium model, though the term freemium can be used to describe other payment methods too. In this plan, your app is free to download, but if the customer wants all the features, you charge for them in-app. Like the option above, it’s a simple method and very effective.
However, just like collecting payment to download the app, Google and Apple keep 30% of these purchases. If you are selling content that is “delivered” via the app itself then you can’t avoid this 30% fee. The concept of “delivered” via the app is a critical one. Some apps, for example, Uber, do not pay the 30% fee, even though Uber will charge you in the app itself. The key here is that the content or service is delivered out of the app. In this case, the phone can’t pick you up and drive you around (at least not yet!), so Uber does not pay the fee. For an alternative example think of Audible. Their books can be delivered in the app. For this reason, Audible won’t let you buy an audiobook in-app, you need to buy audiobooks on their website. The Audible app just lets you download what you have already bought.
Apple and Google are quite strict about enforcing this rule. It’s sometimes hard to figure this out if your content/service is delivered in-app or out-of-app, but we can help you figure this out.
The “in-app purchase” model is great if your app has a low price, think $0.99 to $4.99 features that you can buy. Also if you have some free content that is valuable without the purchase. However, if you don’t have these low priced features, or have a strong web presence, it’s likely best to avoid the 30% fee, and use another option.
Now we are getting to the fun options, at least from a technical standpoint. In this case, we have a mobile app that is free to download in the app store and there are no premium options that you pay for directly to the app store. However, you can buy things inside the app, such as premium content and the app has a web server backend, that will hold all the customer information and credit card data. It’s definitely more complicated than just collecting payment directly in the App store, but you can avoid the 30% fee.
As mentioned above, Apple can be a bit finicky on approving apps that collect payment outside of the app. They, of course, want their 30%, but there are plenty of apps that allow for payments on the website. For example, an e-learning app that students use to take photos for a portion of a class, but use a web app to complete their course. In this case, you can give your app away for free and then have the students pay for the course online. Another example would be having a mobile app that is used by someone who is out in the field, say doing construction, but the field users are managed via a web app. The field users download the app for free, and you charge the web users online. The field user app isn’t useful without a web account to create the logins.
If you’re designing your app to avoid paying Apple’s fees, then having web-based payments is a great way to do it. However, care must be taken to ensure the user experience is smooth. Take a look at an app like Audible, your account and credit card are entered into the web app, then when you download the mobile app, you just need to sign in. The development team still needs to implement things like “Forgot Password” capabilities on the mobile app, so there is some overlap for user account work. These types of app features aren’t always necessary if you’re just taking payments in the App stores.
Technically the general flow is that a user logs in on the mobile app; the mobile app will connect to the web server backend to verify the account via an API; then, over the API, credentials, and content are sent back to the app. This is all done securely over SSL. Care needs to be taken to make sure user accounts, EULAs (End User License Agreements), and forgot password features all work seamlessly with the web server’s API.
Another bonus is that if you’re collecting payments in your web app, you can more fully control features and content on your mobile app. Often the best plan as discussed above is to give your app away for free, and then handle the payment on the web app. Now we have full control over all features in the mobile app via an API and can turn them off or on based on the plan we sell in the web app.
None of these technical details are challenging, but they do take time. The question is whether it’s better to invest this time and skip the 30% fee, or if you are better off just letting the App store collect payments. We can help you decide. Of course, if you’re collecting any payment, you still will be charging a credit card and paying about 3%. Which brings us to the next method. . .
Whether your app is mobile and web or just web, a great option is to collect payments inside of your web app. About half of our customers choose this option and for good reason. It offers the most flexibility and the lowest on-going costs. Since it’s your own custom payment solution in the app, you have the flexibility to choose and change your versions of payment. Setting up thresholds for “freemium” content, having free trials, adding in tiers of subscriptions, having one time payments and then lower monthly subscription fees, turning on and off options are all available to you.
There are some upfront and ongoing security costs. Your site needs to be secure, as well as PCI compliant. User accounts and payment methods are prime targets for hackers, so once you go down this road you need to plan to invest in the maintenance and upkeep of your site. All that said, you have complete control when using a web app for payment collection. Your users will create accounts on your website and then enter credit card information. You choose if there is a one-time fee or a subscription.
It’s important to know how the payments are processed, as there are a few choices. It’s simplest to think of credit cards being run through two steps. The first is the payment gateway, which is basically the tools to get the credit card information. Think of the payment gateway as the credit card machine on your website. It’s where users enter their credit card info and it authorizes the card. To actually get the funds from the credit card to your bank account requires the second part, a merchant account. The merchant account is a bank account that processes the credit card and collects payment and sends it to your bank account. You need both a payment gateway and a merchant account to complete a credit card transaction.
To further simplify this process there are companies that combine the two steps. Companies like Square, Stripe, and even Paypal, will do this for your site. For the ease of combining the payment gateway and merchant account into one, they will charge 3% plus a transaction fee.
3% does not seem like much, but if you are collecting $100,000 per month, that’s $3,000 per month or $36,000 per year. If it’s $1,000,000 per month then it will cost you $360,000 per year. By having a separate merchant account and payment gateway, you can get the fees down to 1.5% or close to half of the price for the bundled service. Therefore, larger companies almost always have separate merchant accounts and payment gateways.
It really isn’t much harder technically to have separate payment gateways and merchant accounts, so if you’re willing to spend the few hours getting them set up at the beginning, you can increase your profits by 1.5% which could be huge over time. Companies like Authorize.net allow developers to set up the payment gateway and merchant account separately and to do so without storing credit cards on your site.
Hopefully, as payment methods continue to get more and more diverse, we can get away from the high-priced options and get closer to 1% fees for processing payments, but we’re not there yet. However, regardless of the payment gateway/merchant account we set up, the option of collecting payments on your web app is the most flexible choice.
CMS systems like WordPress are great for your “brochure” site. Many, if not most, of the apps we develop at Woodridge use some form of public-facing marketing site, which is often built using WordPress. The Web app that Woodridge will build will typically not be WordPress, as our apps tend to have far more features and are more robust than a platform like WordPress can support. So a very common case is that there are two websites – a WordPress or other CMS website for marketing and the Web App for the technology. This is not inherently a problem and it generally makes the most sense. Since WordPress is relatively easy for a non-technical user to manage, it’s great for marketing. However, your web app generally needs features that WordPress won’t support, so it’s separate. For most of our apps, the end user doesn’t even know that he is going back and forth between the two apps.
So why not use WordPress to collect the payment? WordPress has some very slick e-commerce capabilities that make it easy to collect payment, such as the WooCommerce plugin. With little to no technical knowledge, you can set this up. However, if your app is subscription-based (as most are these days), you now will need to tie in your WordPress database users with your mobile and web app database users, and this is not always seamless. WordPress does have some single-sign-on (SSO) capabilities to make this easier and plugins like WooCommerce do an adequate job of supporting subscriptions, but integrating things like free trial periods and multiple payment options or supporting changes to the main account email start to get tricky when using WordPress to collect payment.
Using WordPress, or a WordPress plugin like WooCommerce, is a valid option and it can be set up quickly. It’s best used if you don’t have a complicated pricing model and are not expecting it to change much. You will still need to set up a payment gateway and a merchant account as mentioned above, but that’s very straightforward. If you already have a CMS for your marketing site and your payment collection plans are simple, then it might be the way to go for your app. However, it’s a choice that comes with the limitations of the CMS, so it’s a decision that needs to be made carefully.
The old school method of simply setting up your customers with an account to your web or mobile app and then sending them an invoice is still completely valid. In fact, we often recommend this to customers who have only a few (1000 or less) customers and whose apps sell for larger amounts ($5,000 or more per year).
If you’re collecting $50,000 from 100 customers, there is no reason to give up 2-3% to the credit card processing companies or gateway+merchant processors like Stripe and Paypal. Simply send the customers an invoice. This is particularly true if your customers are blue-chip types with whom you have a good relationship. You’ll notice there is no payment option on the Woodridge website or those of most custom software development companies.
Another situation where this is a great option is when you’re just starting out. Your pricing model is not proven. Will your subscription idea work or will your customers prefer a one-time license? Maybe you need to charge your customer’s customers, not the customer directly. You can save development costs by starting out with a straightforward traditional invoicing plan. However, you do want your development team to be aware of the different pricing models you’re considering, so when/if you do go with taking payments via the app, your app is built to support it.
If you made it this far, you can see that there are trade-offs with each of the methods for getting money from your customers’ bank accounts into yours. Decisions on how to collect these payments are important and can make or break your app’s success.
It’s important to work with a partner who is able to support multiple payment methods. I’ve seen development shops have their “favorite” payment method and then force all apps they build into it. You need a partner that’s flexible and will do what’s right for your app. Things change. Often, you may think one option is the best when you first plan your app, only to find another option is the one your customers prefer. The right development partner will be flexible and build an app that can change with you and your customers. Regardless of the payment method chosen, it’s key that the user experience is smooth. Forgot Password needs to work, subscription notifications need to be timely and send users to the correct spot to renew. A perfect payment method will feel natural to your user base and encourage them to buy your app and that’s the real goal – creating an app that is successful and profitable.