Actions Anywhere

One config. Every OS surface.

iOS Android
$ composer require all1web/nativephp-actions-anywhere
Actions Anywhere — One config. Every OS surface.

One Laravel config turns your app’s actions into Siri phrases, Shortcuts-app actions and Spotlight results on iOS — and Quick Settings tiles and automation links on Android. No Swift, no Kotlin, no Xcode.

  • Siri phrases, Shortcuts actions and Spotlight results on iOS
  • Quick Settings tiles and automation links on Android
  • Declared once in config — no native code to maintain

Documentation

Synced from GitHub 0 seconds ago

🗣️ nativephp-actions-anywhere

One action. Every way in.

Actions Anywhere — Siri, the Shortcuts app, Spotlight, Quick Settings tiles, NFC, QR and user routines, all from one Laravel config

Your users say "Hey Siri, log water in YourApp" — Siri answers out loud, the app never opens, and the invocation lands in your Laravel code as a typed object, ready for a handler.

Your users pull down the Android shade and tap your tile where it sits between Wi-Fi and the flashlight — the action fires from the notification shade, over whatever app they were in, without a launch. On Android 13 and up you can offer the tile in a one-tap placement prompt instead of asking them to hunt through the edit gallery.

Your users search their phone for something they half-remember, and your actions are in the Spotlight results as tappable rows — found the way they find everything else, with nothing to install and no API call from you.

Your users open the Shortcuts app to build a 6am routine, and your actions are in the picker as building blocks, sitting alongside Apple's own. What they assemble is theirs; your handler just runs when their morning does.

Your users tap their phone to an NFC sticker on the fridge, or scan a QR on a poster or a table tent, and land exactly where you sent them — each tag or code carrying its own input, so the same action means "kitchen" on one sticker and "garage" on the next. Links always open the app and run your middleware first: a URL anyone can fire is never allowed to fire a handler silently.

Every one of those is the same action, declared once. You never write a line of native code — the plugin handles the Kotlin and Swift side for you.

Config to compiled intents to every OS surface, back into your Laravel handler

Don't confuse this with home-screen quick actions. Three different things in this ecosystem are called "shortcuts". The community matildevoldsen/quick-actions plugin covers launcher shortcuts — the menu when users long-press your app icon. This plugin covers a different mechanism: Siri voice phrases, Shortcuts-app actions, and Spotlight results via Apple's App Intents framework on iOS, and the Quick Settings shade on Android. (Both plugins can put entries in Spotlight — they're complementary, and many apps want both.)

Why this needs a plugin at all: no WebView, no HTML API, and no PWA can register a Siri phrase, place a row in Spotlight, or drop a tile in the Android shade. Those are OS-level capabilities reserved for native apps, granted only to code compiled into the binary. This plugin is that capability, delivered as one config file. It's the only App Intents / Siri plugin in the NativePHP ecosystem.


🎬 What your users can suddenly do

They do this… …and this happens
🗣️ "Hey Siri, log water in YourApp" Siri confirms out loud, app stays closed. Your handler runs next time they open it.
🔍 Search their phone for your app Your actions appear in Spotlight as tappable rows
🎛️ Pull down the Android shade Your action sits next to Wi-Fi — one tap, no app launch
🏷️ Tap their phone to an NFC sticker Your app opens exactly where you sent them
📸 Scan a QR on a poster or table tent Same action, and each code can carry its own data
🌅 Build a 6am routine on their phone Your action is one of the steps they can pick

All six from one config file. See the full recipes →

✨ What you get

  • 🗣️ Siri phrases with zero user setup — your phrases register the moment the app installs. No shortcut to add, no recording, nothing for your users to enable or discover.
  • 🔒 Nothing gets lost. If your app wasn't running when the user spoke, the invocation waits safely in a native queue and is there the moment your app opens — cold launch, background, or force-quit.
  • 📇 A place in Spotlight and the Shortcuts app — every action becomes a searchable row and an automation building block, automatically, with no extra API to call.
  • 🎛️ Six tiles in the Android shade — your actions next to Wi-Fi and Bluetooth, one tap from anywhere, plus a one-tap placement prompt so users don't have to hunt for them.
  • 🏷️ Every action gets a URLAppIntents::link() hands you the trigger to write to an NFC sticker or encode as a QR code, optionally cryptographically signed so only the codes you generated are accepted. Automation apps and user-built routines can use them too.
  • 🐘 It's all just PHP. Actions are config; invocations arrive as typed objects through an invokable handler class you already know how to write. No Swift, no Kotlin, no Xcode project surgery.
  • Instant or in-app, your choice — background actions finish inside Siri without launching anything; open actions bring the app to the foreground and land the user on exactly the screen you name.
  • 🔁 Change the words without a rebuild — Siri's spoken replies live on the runtime side, so copy tweaks apply on the next app boot.
  • 🩺 php artisan appintents:doctor — diagnoses your whole setup (registration, action config, stale builds, live bridge state) and tells you the exact command that fixes whatever's wrong. Its companion appintents:list shows every action and exactly which surfaces it reaches.
  • 🧪 Testable without a deviceAppIntents::fake() queues invocations exactly as the native layer emits them, with assertions for what your handlers received. 133 automated tests stand behind the plugin itself.
  • 🪶 Invisible to app review — no entitlements, no runtime permissions, no background modes, no extra build targets, no signing changes.

🚀 On the roadmap (planned)

  • 🎯 Typed per-action parameters: structured inputs beyond the single free-text field, so Siri can capture a date, an amount, or a picked item and hand it to your handler already parsed.
  • 🌍 Localized phrase catalogs: per-locale phrase sets so your Spanish and Japanese users speak to your app in their own words.
  • 💡 Siri suggestion donations: teach iOS when your actions matter, so the right one is proposed on the lock screen before anyone asks.
  • 🎨 Per-action Android tile icons: distinct glyphs per tile instead of the shared default.
  • 🔀 Stateful toggle tiles: tiles that show on/off and flip it — "Focus mode", "Clock in/out", "Available for calls" — instead of firing a one-way action. Your app pushes the current state so the shade always reflects reality rather than the last tap, and the tile answers with the new state when the user changes it.
  • 🤖 Android voice via Gemini AppFunctions (Android 16+) — the honest Android analog of Siri App Intents. Google hasn't opened it to third-party invocation yet; the day it ships publicly, this plugin's action schema already fits it. See 🤖 Android.

📦 Install

composer require all1web/nativephp-actions-anywhere
php artisan native:plugin:register all1web/nativephp-actions-anywhere
# Early access via GitHub (licensees with repo access):
composer config repositories.actions-anywhere vcs https://github.com/all1web/nativephp-actions-anywhere
composer require "all1web/nativephp-actions-anywhere:dev-main"

# Local checkout (plugin development):
composer config repositories.actions-anywhere path ../nativephp-actions-anywhere
composer require "all1web/nativephp-actions-anywhere:*@dev"

Publish the config, define an action, then rebuild:

php artisan vendor:publish --tag=appintents-config
php artisan native:run ios

The rebuild matters: Siri phrases, Spotlight entries and tile labels are compiled facts — iOS reads them from your app's binary at install time, so they only exist after a build that included them. That's also why the build has to come from the NativePHP CLI: a build started inside Xcode skips the plugin pipeline entirely, and your new actions silently won't appear.

🧑‍💻 Use it

// config/appintents.php
'actions' => [
    'log-water' => [
        'title'   => 'Log water',
        'phrases' => ['Log water in ${applicationName}'],
        'icon'    => 'drop.fill',
        'mode'    => 'background',
        'dialog'  => 'Logged.',
        'handler' => \App\Actions\LogWater::class,
    ],
],
// app/Actions/LogWater.php
use All1web\AppIntents\Support\IntentInvocation;

class LogWater
{
    public function __invoke(IntentInvocation $invocation): void
    {
        WaterLog::create(['note' => $invocation->input]);
    }
}

That's genuinely the whole integration. The user speaks the phrase — or taps the Android tile, or scans the QR code — and your handler runs with the invocation: immediately for open actions, on the next app open for background ones. On iOS, Siri replies with your dialog.

// Android: put the same action in the Quick Settings shade
'tiles' => ['log-water'],

// …and offer one-tap placement (Android 13+)
AppIntents::requestTile('log-water');

Want it on an NFC sticker or a QR code too? You've already written it — docs/RECIPES.md has the complete builds.

Using JavaScript instead? (Inertia / Vue / React)

// vite.config.js — alias the wrapper once:
// '@app-intents': '/vendor/all1web/nativephp-actions-anywhere/resources/js/appIntents.js'
import appIntents from '@app-intents';

const invocations = await appIntents.pending(); // set APPINTENTS_AUTO_DRAIN=false first

The wrapper exports one function per bridge call (pending, count, hasPending, clear, sync, status, requestTile) and degrades gracefully in the browser. See docs/REFERENCE.md for the drain-owner rule before pulling from JS.

🍏 iOS

This is where the plugin is strongest — and it's the platform that needs no user setup at all. Your phrases, Spotlight rows, and Shortcuts-app actions register when the app installs. There's no companion shortcut to distribute, nothing to record, and nothing to explain in your onboarding.

Siri speaks your configured reply, not live PHP. There's no synchronous channel from native code into a running Laravel app, and Siri needs an answer in about a second — so the spoken response is a template you write (with {input} interpolated), and your handler runs on delivery. If an action genuinely needs live data in its answer, make it an open action and show the real number on screen. Background invocations are processed the next time the app opens: say "Logged — syncs when you open the app" rather than implying instant server-side writes.

Ten actions may carry Siri phrases (Apple's cap). Extras still work as Shortcuts-app actions — the generator tells you exactly which ones spilled over, so you choose rather than discover it in the wild.

🤖 Android — real surfaces, honest limits

Android gets Quick Settings tiles and action links — real, supported OS surfaces:

'tiles' => ['log-water', 'start-workout'],   // up to 6, in the shade

Tap a tile: background actions queue instantly without opening the app; open actions foreground it onto the action's url. And every action answers at /appintents/run/{action} — set NATIVEPHP_DEEPLINK_SCHEME (NativePHP's built-in deep-link feature) and NFC tags, QR codes, automation apps, and user-built routines can all trigger your Laravel code by opening a URL.

These are ordinary Android tiles, which means anything that can activate a tile can run your action — potentially including assistants with device control, which on some skins can reach a tile by its visible name. We have not verified that on any specific device and it is not a feature of this plugin: treat it as an OEM-dependent bonus, and keep it out of your app's copy. What is dependable on Samsung needs nothing from you either: a routine that opens your action's URL, started by a voice command the user picks.

What Android does not get is built-in voice — your actions don't register phrases with an assistant the way they do with Siri, and we'd rather tell you why than sell a checkbox. Google Assistant's per-app actions are being retired with Assistant itself; Gemini's replacement (AppFunctions, Android 16+) isn't open to third-party invocation yet and is first on our roadmap the day it is. Bixby's own SDK path (capsules) is a separate Samsung-built artifact no app package can carry. So: advertise tiles and links freely, but don't claim built-in Android voice support in your app copy.

🤝 Plays well with others

ALL 1 plugins are built to co-install: no shared runtime symbols, no shared storage, and no contention for the launcher shortcut budget — this plugin never touches ShortcutManager at all, so it can't evict anyone else's entries. Run it alongside the community quick-actions plugin and your users get long-press shortcuts and voice, Spotlight, tiles and scan triggers, each on its own surface.

🧹 Uninstall

Leaving is as clean as arriving — the plugin never edits your project files, so removal is two commands:

php artisan native:plugin:uninstall all1web/nativephp-actions-anywhere
php artisan native:install

The rebuild regenerates the native projects template-fresh (overwriting is the default), so no generated code and no OS registrations survive. One thing to plan for rather than discover: users who built their own automations on your actions will see those stop working — so if you're retiring a single action rather than the whole plugin, keep its id alive pointing at a graceful handler for a release or two. Migration rules →

📋 Requirements

NativePHP Mobile ^4.0 for builds (the plugin-hook system powers code generation and tile labeling); installs alongside ^3.0
PHP ^8.2
iOS 18.2+ — follows your NativePHP project's floor
Android 8.0+ (minSdk 26); add-tile prompt on 13+; voice parked (see above)
Permissions None. No runtime permissions, no usage-description strings

🔬 Digging deeper

Doc What's in it
Recipes 🍳 Complete copy-paste builds: hands-free logging, NFC stickers, QR check-ins, tiles, routines, structured input, testing
Reference Full API: config fields, facade calls, IntentInvocation, events, testing, diagnostics, migration rules
Design Architecture and rationale: the build/runtime split, why dialogs are templates, the drain pipeline
Platform notes Platform realities: the ten-phrase cap, phrase rules, tile behavior, the Android verdicts
Store review What Apple/Google review sees (nothing to declare)
Upgrading What changed between versions and the one config note that matters
Changelog Version history

🛠️ Development

composer install
composer test

🔍 Under the hood

The fine print — everything below is why the handful of lines of PHP above just work.

⚙️ Engineering you don't have to think about: your action list is compiled into native Swift App Intents by a build hook on every CLI build — deterministically, with hard validation, so a phrase Siri could never match fails the build with a message telling you why instead of failing silently on a user's phone. Invocations persist to a lock-guarded native queue before PHP is even awake, so a cold-launch Siri command survives to the next app open. Tile slot names are frozen contracts enforced by tests, so placed tiles survive every update.

🧪 Verified, not vibes: the platform constraints this is built on — install-time phrase registration, Apple's ten App Shortcut slots, background launch behavior, the compiler's hook ordering, Android's tile lifecycle — were verified against vendor source and current platform documentation before the first line of code. 133 automated tests pin the manifest, generator output (golden-file, escaping, caps, determinism), invocation normalization, the config contract, and the shipped Swift and Kotlin surfaces. php artisan appintents:doctor re-verifies your own setup any time.

🔧 We fix what we find: every batch goes through adversarial pre-release audits — independent passes over the PHP runtime paths and over both native platforms — and they earn their keep. They caught a bridge parsing bug that would have shipped Quick Settings tiles which looked perfect and did nothing; a runtime kill switch that could never reach the device; an open redirect on the path every Siri phrase takes; tile slots that silently renumbered when you defined a new action, repurposing tiles users had already placed; and a queue that could deliver the same invocation twice after a process death. All fixed before you could meet them, each with a regression test, and the platform realities we can't fix are documented in docs/PLATFORM-NOTES.md so you never debug them yourself.

🏪 Review-proof by design: zero runtime permissions, zero usage-description strings, no private APIs, no extra build targets, no signing changes — invisible to Apple/Google review and safe in any cloud build pipeline. Details: docs/STORE-REVIEW.md. Your AI pair-programmer gets first-class knowledge too: Laravel Boost guidelines ship in the box.

📜 License

Commercial. Distributed as a paid plugin via the NativePHP Plugin Marketplace; each purchase grants a license key used for Composer authentication. Licensed by ALL 1, a Wyoming corporation. Source access is included for your own development; redistribution of source is not — see LICENSE for the full EULA.