mob_sms
SMS composer for Mob apps. Opens the user's default messaging app pre-filled with recipient + body; the user taps Send to actually send. No dangerous permissions on either platform. Cross-platform surface (MobSms.compose/2), per-platform delivery asymmetry documented honestly.
Install
Requires mob 0.9.0 or newer.
def deps do
[
{:mob, "~> 0.9.0"},
{:mob_sms, "~> 0.1"}
]
end
In mob.exs, activate the plugin:
config :mob, :plugins, [:mob_sms]
Usage
MobSms.compose(socket,
to: "+15551234567",
body: "Join me on Sample App: https://example.com/i/ABC123"
)
Both :to and :body are optional. Omit :to to let the user pick a recipient from Contacts inside the composer.
Result arrives as a message to the calling process:
def handle_info({:sms, :sent}, socket), do: ... # iOS
def handle_info({:sms, :cancelled}, socket), do: ... # iOS
def handle_info({:sms, :composer_opened}, socket), do: ... # Android
def handle_info({:sms, :not_available}, socket), do: ... # both
Per-platform delivery — the asymmetry to know
-
iOS —
MFMessageComposeViewControlleris presented as a sheet inside your app. The system delegate reports:sent,:cancelled, or:failedreliably.:not_availablemeans the device cannot send SMS (simulator, no cellular / iMessage capability, no SIM). -
Android —
Intent.ACTION_SENDTOwithsmsto:opens the user's default SMS app externally. Android does not reliably tell the host app whether the user tapped Send or cancelled — most SMS apps do not set an activity result. The plugin delivers:composer_openedonce the composer is showing (or:not_availableif no SMS-capable app is installed) and stops there. If knowing what the user did afterwards matters to your flow, plan around this asymmetry rather than assuming a:sent.
This asymmetry is by design at the platform layer, not something the plugin can paper over. Android intentionally hands the user off to a separate app rather than embedding a sheet; iOS presents inline and can observe the outcome.
Common use cases
- Invite codes — "Join me on X, here's the link" — the canonical fit
- Share a link / share a file — user picks a friend inside the composer
- Tell a friend — referral flows without your app needing to know the friend's number
- Verification workaround — send a code to a manually-provided number without SMS gateway costs
What this plugin is NOT
Not silent-send. iOS has no public API for sending SMS without the user tapping Send; Apple treats that as a bright-line spam surface. Android can silent-send via SmsManager.sendTextMessage under the SEND_SMS runtime permission, but Google Play rejects that permission request for most non-SMS-centric apps (the "Permissions Declaration" gate).
If you have a real reason to bypass the sheet on Android — and can accept iOS being permanently in composer mode — a separate send/2 on this module can land in a later release. Talk to us before designing around it.
Related
- MOB epic MOB-257 — the mob_wake plugin arc, which covers the receive side of push notifications for apps that want the "wake me when something happens" flow that people often reach for background tasks to build.
License
MIT.