sparkworldke/nativephp-sms-reader-bridge
NativePHP SMS Reader Bridge integrates NativePHP with Laravel to let your app read SMS messages from the device inbox. It provides a straightforward API for querying messages and building SMS-powered features such as verification, notifications, and message-based workflows.
composer require sparkworldke/nativephp-sms-reader-bridge
Note the release text says "after the package is submitted on Packagist" — verify the package actually resolves on Packagist (or add the VCS repository) before you build a workflow around it.composer update alone will not register the bridge.SmsReader facade/class (getMessages, getMessagesForSenders), then the SmsReceived event class, then the TypeScript definitions shipped with the JS bridge — the TS defs are the fastest way to see the real payload shape (field names, timestamp format, folder enum values).READ_SMS, call SmsReader::getMessages(limit: 50), render into a table. This exercises permission flow, the query API, and payload shape end-to-end with the least surface area.Permission-gated onboarding flow. Treat SMS permission as a first-class UX state, not an afterthought. Drive a state machine: not requested → denied → granted. The release notes mention "runtime READ_SMS / RECEIVE_SMS handling," but do not document the exact denial/exception surface — so wrap your first call in a try/catch and log the raw result to discover the real behavior on-device. Gate every read behind an explicit user action (a tap), not app boot.
Querying with filters. Two entry points:
SmsReader::getMessages() — all senders, with limit, since, and folder.SmsReader::getMessagesForSenders() — add a sender list to narrow to known numbers (e.g., your bank's shortcode, OTP senders).Practical patterns:
limit. The default is undocumented in the notes; an unbounded inbox read on a device with 20k messages is a real stall risk.getMessagesForSenders(senders: ['MPESA', '+2547...'], limit: 5) is far cheaper than reading the whole inbox and filtering in PHP.since for incremental sync rather than re-reading everything and deduping client-side. Confirm the timestamp unit on-device (millis vs. seconds vs. ISO string) — this is the single most likely silent bug.folder values are all, inbox, sent, draft, outbox, queued, failed, spam. See gotchas: not all folders exist on all OEMs.Event-driven ingestion with SmsReceived. For real-time flows (OTP autofill, live transaction feed):
getMessages() backfill doesn't duplicate.since-based reconciliation query.Multi-part SMS. Long messages arrive as segments. The package reconstructs them, but reconstruction only works if all parts are actually present on-device. Design your parser so that a truncated body fails gracefully (e.g., OTP regex finds nothing → prompt "retry") instead of throwing.
Architecture tip: isolate behind your own repository. Put a SmsRepository interface between your app and SmsReader. You get: (a) a fake implementation for tests and CI where no native bridge exists, (b) an iOS no-op, (c) a cheap swap if this fork stalls. Given this is a fork of another package, that abstraction is worth the twenty minutes.
Server sync pattern. If you forward messages to your Laravel backend, sync on a queue after local persistence, send a stable client-side UUID, and let the server upsert on it. Never block the native read on a network round-trip.
Google Play policy is the biggest risk. READ_SMS / RECEIVE_SMS are restricted permissions. Google Play only grants them to apps whose core functionality is SMS handling (default SMS handler) or a narrow set of permitted use cases. A CRM or fintech app reading the inbox via this package will likely be rejected at review. Check your distribution channel (Play vs. enterprise/sideload) before building. This is the number-one reason to pick this package up or drop it.
Android only. No iOS implementation is claimed. Every call site needs a platform guard, and your feature must degrade to manual entry.
Packagist availability. The release note hedges with "after the package is submitted on Packagist." If composer require fails, add a vcs repository entry and pin to v1.0.0 — and pin it, because a fork with one release can move under you.
Folder availability varies by OEM and Android version. queued, failed, outbox, and spam are not consistently populated across Samsung/Xiaomi/AOSP builds. Build the folder selector as an opt-in advanced filter rather than the primary UI, and never assert "no messages" from an empty folder result.
Multi-part reconstruction edge cases. Out-of-order arrival, missing middle segments, and carrier-specific concatenation headers can all produce partial bodies. Validate reconstructed text length/sentinel before parsing (especially for OTPs and JSON payloads).
Timestamp semantics are undocumented. Verify since and the message timestamp field on a real device early. Store as UTC on your side; device timezone drift is common.
Emulator testing. You cannot receive real SMS in an emulator easily. Seed the inbox via adb emu sms send <number> <text> for the event path, and push a pre-populated mmssms.db (or use a physical device) for the read path. Test both — they exercise different code.
Debugging the bridge. NativePHP bridge errors often surface in adb logcat rather than the Laravel log. When a call returns empty or throws, check logcat filtered on your app package before assuming a PHP bug. Also confirm the TS definitions match the runtime payload — forks frequently lag on this.
Permission revocation mid-session. A user can revoke SMS permission in Android settings while your app is backgrounded. Re-check before every read; don't cache "granted" in app state indefinitely.
Extension points. The documented surface is deliberately small (two read methods + one event). There's no documented config file or query builder. If you need custom filtering (e.g., by body regex, date range), do it in PHP after the native call with a tight limit — don't expect the package to grow a query DSL. The SmsReceived event is your only injection point for real-time behavior; wrap it in your own event if you need fan-out.
Fork risk. One release, single maintainer, forked from atendwa/nativephp-sms-reader. Check the upstream for issues that may also affect this fork, and watch for unmerged fixes. Keep your repository abstraction in place so an exit is a one-file change.
Testability. Assume no test suite ships with it. Your own tests must mock the facade (SmsReader::shouldReceive(...)) and the SmsReceived event. Verify payload shape with a captured real-device fixture.
How can I help you explore Laravel packages today?