Answers · Mobile

How do I tell if a request came from the native mobile app?

Use the hotwire_native_app? helper in app/controllers/application_controller.rb. The shells append "Hotwire Native" to the user agent, and the helper reads it. That check is how you show the native purchase trigger in the app and the Stripe button on the web, which the store rules require you to get right.

The helper

hotwire_native_app?          # true in either shell
hotwire_native_android?      # true in the Android shell specifically

Both are declared as helper_method in app/controllers/application_controller.rb, so views can call them directly. The Android-specific one exists because the two platforms differ on what has to be hidden, not because the code needs to know which phone it is talking to in general. The shells that set the user agent are in mobile/ios and mobile/android.

The case that actually matters

<% if hotwire_native_app? %>
  <%= link_to "Subscribe", iap_subscribe_path %>
<% else %>
  <%= button_to "Subscribe", checkout_path %>
<% end %>

Showing a Stripe checkout button inside the iOS app is the most common reason an app of this shape is rejected. Apple requires digital subscriptions to go through StoreKit, and a link out to an external payment page is what reviewers look for.

Do not use it for authentication

A user agent is a string the client sends and anyone can set. It is fine for deciding which button to render and wrong for deciding who someone is or what they may do. Entitlement still goes through Entitlement.for(Current.account) and record access still goes through Pundit, regardless of the client.

Use it sparingly

Every branch on this helper is a second version of a page that has to be kept working. Two or three in an app is normal: the purchase trigger, the subscription management link, and perhaps hiding a footer. A dozen means the app and the site have quietly become different products.

Check it while developing

bin/dev

Then load a page in the shell and one in a browser side by side. If you want to test the branch without building, override the user agent in your browser's devtools to include "Hotwire Native" and reload. That is faster than a rebuild for checking which button renders.

Related questions

Do I have to use Apple's in-app purchase for subscriptions?

Inside the app, yes, for anything digital your users consume in the app. Apple takes 15 to 30 percent and rejects apps that link out to an external checkout for it. On the web, in a browser, you keep using Stripe. The same account can be entitled by either path.

How does a native in-app purchase activate access on my server?

The app completes the purchase natively, then posts the receipt to /iap/purchase. Your server verifies it with Apple or Google through the store adapters and calls the same Subscription.activate! a Stripe checkout would. One entitlement row, two possible ways of paying for it.

How much do Apple and Google take from an app subscription?

Fifteen percent for developers under the small business thresholds on both platforms, thirty percent above them. Apple's programme applies under one million dollars a year; Google's reduced rate applies to the first million. Neither is automatic: you apply. Stripe's fee on the web is under three percent, which is the comparison that matters for pricing.