Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nativephp Wifi Direct Laravel Package

protendai/nativephp-wifi-direct

View on GitHub
Deep Wiki
Context7

Getting Started

This is a first public release (v1.0.0, MIT), so there is no upgrade path to worry about — but also no battle-testing behind it. Treat it as a young package and budget time for device testing on real hardware rather than simulators.

  1. Install and wire up the bridge. Add the package via Composer and build the JS entry (resources/js/index.js) with your app assets. Native sources now live under resources/android/src and resources/ios/Sources — if you have a custom native build step, point it there. Follow the README's install section for the exact commands; it's the authoritative source for this release.
  2. Read the README's "Known issues" first. iPhone joining an Android-hosted group is explicitly experimental (an iOS device refused to associate with a Galaxy A05s host on 2.4 GHz). If your first use case is cross-platform, you are on the risky path — prototype same-platform first.
  3. Check the platform declarations. iOS NSLocalNetworkUsageDescription is declared by the plugin, and Android permissions are requested at runtime. Verify what actually lands in the merged manifest / Info.plist of your app shell, since host apps often override these.
  4. First use case: host/join. A host validates a network name and passphrase with WifiDirect::isValidNetworkName() / WifiDirect::isValidPassphrase(), calls createGroup(), renders a QR pairing code, and listens for Connected. A guest scans the code, hands the payload to parsePairing(), and calls connect().

Start in PHP only. Get a host/join round trip working through the facade and Laravel events before you add the Inertia/Vue/React layer — it isolates whether a failure is native, PHP, or front-end.

Implementation Patterns

Validate credentials in PHP before you call native. The headline Android fix is that malformed credentials crashed the app inside WifiP2pConfig.Builder. The package now validates in PHP, JS and natively, but you still want the PHP check for UX: reject bad input with a form error instead of a silent false from connect().

$name = trim($request->input('network_name'));

if (! WifiDirect::isValidNetworkName($name) || ! WifiDirect::isValidPassphrase($request->input('passphrase'))) {
    // return validation error, never reach the bridge
}

Treat connect()'s bool as the primary result, events as follow-up. connect() now returns false — with no event — for malformed credentials or when the device refuses the call. So:

if (! WifiDirect::connect($ssid, $passphrase)) {
    return back()->withErrors(['pairing' => 'This device refused the connection request.']);
}
// only now start waiting for Connected / ConnectionFailed

Model host and join as two explicit flows, not one generic "sync" method. Because createGroup() and connect() cancel each other, an accidental double-invocation (a double-tap, a retried request, a Livewire re-render) will tear down the flow you just started. Put each flow behind a single action class or service method and guard with a state machine (idle → hosting/joining → connected), ignoring calls unless state is idle.

Handle parsePairing() returning null. Codes whose network name or passphrase are malformed return null rather than throwing. Always branch:

$pair = WifiDirect::parsePairing($scanned);

if ($pair === null) {
    return back()->withErrors(['qr' => 'That QR code is not a valid pairing code.']);
}

Listen on both sides of the stack. PHP events (Connected, ConnectionFailed, Disconnected, PermissionResult, QR scan requests) drive server state; the JS library (Events names, onWifiDirect()) drives the UI. Keep the two thin: the JS side should re-render, the PHP listener should persist. Use the JS Events constants rather than string literals so a rename doesn't silently break listeners.

Permissions are a first-class flow, not a preamble. PermissionResult now carries reason (denied, permanently denied, approximate, interrupted) and a permanentlyDenied flag. The pattern that holds up:

  • denied → explain and offer retry.
  • permanently denied / permanentlyDenied → stop asking, point the user at system settings.
  • approximate (Android 12/12L) → this is the fixed case where precise was requested alone and the permission was silently denied; ask for both, and don't block the UI on a "precise" assumption.
  • interrupted → the request survived activity recreation but did not resolve; re-request on next interaction rather than looping.

Test with the FakeBridge, and use the new macros to pin intent. withWifiDirect() now also answers connect(), and the new assertions let you test the flow rather than the implementation:

WifiDirect::fake()->withWifiDirect();

$this->post('/group', ['name' => 'DIRECT-myApp', 'passphrase' => 'correct horse battery'])
    ->assertRedirect();

WifiDirect::assertWifiDirectHosting();

Pair assertWifiDirectHosting() / assertWifiDirectJoining() / assertWifiDirectDisconnected() with assertQrScanRequested() for QR-driven join screens. Assert the negative too: that a malformed pairing code never reaches connect().

Keep pairing secrets out of persistence. Network names are no longer written to the log, but the passphrase and the QR payload still are secrets. Don't put them in session flashes, debug dumps, error tracking breadcrumbs, or Inertia props you don't need.

Gotchas and Tips

  • disconnect() always emits Disconnected, on both platforms, even with no link. Your listener must be idempotent. Don't use the event to infer "there was a connection" — drive that from your own state.
  • Disconnected can arrive before Connected. Replacing an in-flight or reported link fires Disconnected for the old one first. If your UI treats Disconnected as terminal, a fast host→join transition will look like a failure. Sequence-check with a flow/generation ID.
  • Late Connected after ConnectionFailed is fixed but conceptually still possible on real radios. The Android join is now cancelled and a late-forming group removed — still, don't write listeners that assume strict event ordering without a timeout. Add your own deadline (a queued job or a timer in JS) around every join/host attempt.
  • Hosting does not survive the activity being destroyed. A hosted group or join is now torn down when the activity is destroyed (correctly, not on configuration changes — rotation is safe). Do not treat hosting as a background service: re-establish on cold start, and expect the group to be gone when the user returns from a long background stint.
  • status() is advisory. A first-call enabled: false was a real bug and is fixed by reading sticky P2P state on attach, but status() still can't tell you whether permissions are granted. Gate your UI on permission results and status, not status alone.
  • Local network permission on iOS fails quietly from the user's perspective. The plugin declares NSLocalNetworkUsageDescription, but if the user declines, joins simply won't complete. NWPathMonitor plus an address poll now report the drop — which also means detection is not instantaneous. Don't poll aggressively to compensate; it's the package's job and doubling up wastes battery.
  • Mixed-platform groups: test on hardware, on 2.4 GHz, on the actual model. The Galaxy A05s / iOS refusal is a hardware-level association problem, not something you can code around. If cross-platform is a requirement, design the UX to allow "host here instead" and verify on every device family you support, not just one of each OS.
  • QR rendering changed for a reason. Codes now honour foreground/background colours and are drawn module by module at integer scale (previously interpolated and blurry). If you pass custom colours, keep high contrast, and if you render at a fractional scale in CSS you'll reintroduce the blurriness the fix removed.
  • resources/android/src and resources/ios/Sources are the new native locations. Any custom native patch or build script you wrote against the previous layout needs updating. Also note iOS minimum is now 15.0 — confirm your deployment target.
  • FakeBridge fakes the PHP side. The assertions tell you what the bridge was asked to do; they don't emulate the native radios or the JS event bus. Keep a small, manual, real-device smoke checklist for host, join, cancel, permission-denied, and activity recreation — that's where the interesting bugs in this release lived.
  • Extension point worth using: keep the facade behind your own thin service (e.g. PairingService) so you can swap in a fake, add your own timeouts/state machine, and keep controllers free of event-listener registration. The package's Laravel Boost guidelines and Pest suite are useful references for the intended idiom — read them before inventing your own wrapper.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
htinlynn/genius-helper
maco-studios/hephaestus
elmogy/larafast
xeviant/laravel-paystack
gorilladash/laravel-website-sdk
martialbe/flysystem-oss
chondal/3312client
jeroen-g/flickr
opscale-co/nova-genbi
itsjustvita/laravel-retention
tequilarapido/trackit
gregsphotography/site-builder-filament
cabaoctavio/laravel-query-log
gregsphotography/site-builder-components
io-digital/clickatell
snowsoft/laravel-admin
oxygen/auth
relicsoftware/barakah-payment-gateway
tobya/work-with-composer
equipc/laravel-email-validator