<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Michael Ishri</title>
    <description>The latest articles on Forem by Michael Ishri (@michaelishri).</description>
    <link>https://forem.com/michaelishri</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F196688%2F651c0f56-a42a-40c6-a4fa-e924ff1bbb65.jpeg</url>
      <title>Forem: Michael Ishri</title>
      <link>https://forem.com/michaelishri</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/michaelishri"/>
    <language>en</language>
    <item>
      <title>Bundle Google Fonts with your NativePHP Mobile application</title>
      <dc:creator>Michael Ishri</dc:creator>
      <pubDate>Mon, 17 Nov 2025 21:10:07 +0000</pubDate>
      <link>https://forem.com/michaelishri/bundle-google-fonts-with-your-nativephp-mobile-application-1l84</link>
      <guid>https://forem.com/michaelishri/bundle-google-fonts-with-your-nativephp-mobile-application-1l84</guid>
      <description>&lt;p&gt;If your NativePHP mobile application is using Google Fonts, you can improve the speed of your application by bundling the fonts with your application rather than relying on an internet connection.&lt;/p&gt;

&lt;p&gt;The simplest way I've found to do this is to use the &lt;a href="https://github.com/Log1x/laravel-webfonts" rel="noopener noreferrer"&gt;log1x/laravel-webfonts&lt;/a&gt; composer package.&lt;/p&gt;

&lt;p&gt;First install it as a dev dependency.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;composer require log1x/laravel-webfonts --dev
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then use it's nice TUI to select your font and it's variants.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan webfonts:add
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As specified in the &lt;a href="https://github.com/Log1x/laravel-webfonts/blob/main/README.md" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;, it will download the font, then extract it to your &lt;code&gt;resources/fonts&lt;/code&gt; folder and it will also create a &lt;code&gt;resources/css/fonts.css&lt;/code&gt; file with the correct (relative) imports.&lt;/p&gt;

&lt;p&gt;Finally, you can simply add this to the top of your &lt;code&gt;resources/css/app.css&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@import './fonts.css';
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now when you build,&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the font files will be copied to the &lt;code&gt;public/build/assets&lt;/code&gt; folder&lt;/li&gt;
&lt;li&gt;the css imports will be bundles as part of your &lt;code&gt;app.css&lt;/code&gt; file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I found the log1x package to be better suited to NativePHP mobile applications because of how simple it makes bundling with Vite and the fact that it uses relative imports for the fonts. These two points are the main pain points with the &lt;a href="https://github.com/spatie/laravel-google-fonts" rel="noopener noreferrer"&gt;spatie/laravel-google-fonts &lt;/a&gt; for this use case. I'm sure it's just my inexperience, but I found I had to do a heap of custom Vite plugin stuff to make everything work (with the Spatie package).&lt;/p&gt;

&lt;p&gt;If you choose to use the Spatie package instead, just note that it doesn't spit out relative paths for the fonts (it will hard code your APP_URL). This is fine for applications running on the web but on NativePHP Mobile we don't want that. Knowing this is important because it took me a long time to realise this was slowing the boot time of my NativePHP Mobile application. Essentially, using the import provided by the package, it was trying to load fonts from &lt;code&gt;http://localhost:8000&lt;/code&gt; and eventually timing out then fetching from Google directly. So any subsequent boots would be fine since it had already been cached. But once I figured out that NativePHP applications "run" on &lt;code&gt;http://127.0.0.1&lt;/code&gt;, it was never going to be able to fetch the fonts locally. Once I fixed this, my boot times went from 2-5 seconds to instant.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Please note, I'm not trying to throw shade at the Spatie package / team. I love those guys and the work they do for our community. I'm simply trying to help others that may run into the same problem that I did and to provide a better solution for this use case.&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>nativephp</category>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>Hijack the Back button on Android in NativePHP</title>
      <dc:creator>Michael Ishri</dc:creator>
      <pubDate>Thu, 06 Nov 2025 09:00:43 +0000</pubDate>
      <link>https://forem.com/michaelishri/hijack-the-back-button-on-android-in-nativephp-405b</link>
      <guid>https://forem.com/michaelishri/hijack-the-back-button-on-android-in-nativephp-405b</guid>
      <description>&lt;p&gt;While testing my NativePHP Android application, I noticed that the &lt;strong&gt;back&lt;/strong&gt; button / action wasn't behaving the way I would expect for a regular "native" application. &lt;/p&gt;

&lt;p&gt;I realised that it was behaving like a browser with it's history stack. If I navigated into sub-menus using the UI then started using the &lt;strong&gt;back&lt;/strong&gt; button / action it would just take me back through my history instead of up the menu tree like a regular app would, so I thought I'd look into how to fix that behaviour.&lt;/p&gt;

&lt;p&gt;After a quick Google search, the answer ended up being a simple, single line change. By adding the following to your &lt;code&gt;MainActivity.kt&lt;/code&gt; file, we can instead emit an event in JavaScript which can then be reacted to.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluateJavascript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;window.dispatchEvent(new Event(&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;'native:backpressed&lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;&lt;span class="s2"&gt;'))&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Caution:&lt;/strong&gt; If you take this approach, you need to make sure that &lt;strong&gt;EVERY&lt;/strong&gt; page includes a way to handle the back button / action otherwise you could lock your user in a screen without being able to escape (except by killing the app or going to the Android home screen).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Let's we take a look at the &lt;strong&gt;original method&lt;/strong&gt; surrounding this.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;onBackPressedDispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;webView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webView&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;canGoBack&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;goBack&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the &lt;strong&gt;modified one&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight kotlin"&gt;&lt;code&gt;&lt;span class="n"&gt;onBackPressedDispatcher&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addCallback&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;val&lt;/span&gt; &lt;span class="py"&gt;webView&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;binding&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;webView&lt;/span&gt;

    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;canGoBack&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;webView&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;evaluateJavascript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"window.dispatchEvent(new Event('native:backpressed'))"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;finish&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now in all my Blade views, I can simply add.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;script&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native:backpressed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/home&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="sr"&gt;/script&lt;/span&gt;&lt;span class="err"&gt;&amp;gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Caveat
&lt;/h2&gt;

&lt;p&gt;There is one big caveat to making this change. Whenever the NativePHP team push updates, we may need to run &lt;code&gt;native:install --force&lt;/code&gt; which will overwrite the changes. &lt;/p&gt;

&lt;p&gt;So to workaround this issue, I've created an Artisan console command that can perform the replacement automatically which you would need to run after &lt;code&gt;native:install&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;// app/Console/Commands/InterceptBackButton.php

&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Console\Commands&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Console\Command&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;Illuminate\Support\Facades\File&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InterceptBackButton&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Command&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nv"&gt;$replaced&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * The name and signature of the console command.
     *
     * @var string
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$signature&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'android:intercept-back-button'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * The console command description.
     *
     * @var string
     */&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="nv"&gt;$description&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'Changes the default behaviour of the Android Back button.'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * This helper replaces the default behaviour of the back button on Android.
     * Instead of behaving like a browser, this will instead emit a JavaScript event in your application which can be reacted to.
     * You may listen for the `native:backpressed` event.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;handle&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;collect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;allFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;base_path&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'nativephp/android/app/src/main'&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;fn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getFilename&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="s1"&gt;'MainActivity.kt'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;map&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getRealPath&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$files&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$contents&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="nv"&gt;$updated&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;str_replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                &lt;span class="s1"&gt;'webView.goBack()'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="s1"&gt;'webView.evaluateJavascript("window.dispatchEvent(new Event(\'native:backpressed\'))", null)'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="nv"&gt;$contents&lt;/span&gt;
            &lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$contents&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="nv"&gt;$updated&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nc"&gt;File&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;put&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$updated&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;info&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Success, performed replacement in: &lt;/span&gt;&lt;span class="nv"&gt;$file&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;replaced&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;replaced&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Fail, replacement of intercept code couldn\'t be performed'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've also extracted the JavaScript portion into the following Blade component.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;{{-- resources/views/components/return-to.blade.php --}}

@props(['route'])

&lt;span class="nt"&gt;&amp;lt;script&amp;gt;&lt;/span&gt;
    &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;addEventListener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;native:backpressed&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;event&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;window&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;location&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;href&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;{{ $route }}&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/script&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Which you can use in your view like this;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight html"&gt;&lt;code&gt;    ....
    &lt;span class="nt"&gt;&amp;lt;x-return-to&lt;/span&gt; &lt;span class="na"&gt;route=&lt;/span&gt;&lt;span class="s"&gt;"{{ route('home') }}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/body&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusion
&lt;/h1&gt;

&lt;p&gt;This is really just a proof-of-concept, I haven't performed extensive testing and it may need more work to make it more robust (for example, how do you exit the app once you can't go back any further), but the concept is out there now.&lt;/p&gt;

&lt;p&gt;This exercise has really opened my eyes to the possibilities which is really exciting.&lt;/p&gt;

</description>
      <category>nativephp</category>
      <category>android</category>
      <category>php</category>
      <category>laravel</category>
    </item>
    <item>
      <title>How to sign your NativePHP Android App for the Google Play Store</title>
      <dc:creator>Michael Ishri</dc:creator>
      <pubDate>Thu, 06 Nov 2025 00:31:29 +0000</pubDate>
      <link>https://forem.com/michaelishri/how-to-sign-your-nativephp-android-app-for-the-google-play-store-4hac</link>
      <guid>https://forem.com/michaelishri/how-to-sign-your-nativephp-android-app-for-the-google-play-store-4hac</guid>
      <description>&lt;p&gt;This article explains the basics of getting your NativePHP application to the Google Play Store.&lt;/p&gt;

&lt;p&gt;Before you begin, you will need to &lt;a href="https://support.google.com/googleplay/android-developer/answer/6112435" rel="noopener noreferrer"&gt;register for a Play Console developer account&lt;/a&gt;. It has a one time fee of $25 (at the time of writing). It may take a few days to get approved on Google's side.&lt;/p&gt;

&lt;p&gt;Once you have been approved and your NativePHP application is ready to be uploaded, you need to do the following things.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Generate a keystore file&lt;/li&gt;
&lt;li&gt;Configure NativePHP to use the keystore file&lt;/li&gt;
&lt;li&gt;Publish your application&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Generate your keystore file
&lt;/h2&gt;

&lt;p&gt;You keystore file is a Java thing which is essentially a bag that can hold a bunch of things. In our case, we want it to hold our signing keys for our application (but it could hold many things).&lt;/p&gt;

&lt;p&gt;In a terminal, run the following command (this assumes you already have a JDK installed which comes with the &lt;code&gt;keytool&lt;/code&gt; cli).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;keytool -genkey -v -keystore my-release-key.jks -keyalg RSA -keysize 2048 -validity 10000 -alias my-key-alias
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;my-release-key.jks&lt;/code&gt; will be the filename&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;my-key-alias&lt;/code&gt; is an identifier for your key&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For simplicity, I would recommend you just call both the name of your application.&lt;/p&gt;

&lt;p&gt;Follow the prompts:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enter keystore password: Create and confirm a strong password. This is your password to the keystore file and we'll need to use this later.&lt;/li&gt;
&lt;li&gt;What is your first and last name?&lt;/li&gt;
&lt;li&gt;What is the name of your organisational unit?&lt;/li&gt;
&lt;li&gt;What is the name of your organisation?&lt;/li&gt;
&lt;li&gt;What is the name of your city or locality?&lt;/li&gt;
&lt;li&gt;What is the name of your state or province?&lt;/li&gt;
&lt;li&gt;What is the two letter country code for this unit?&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;yes&lt;/code&gt; when prompted to confirm&lt;/li&gt;
&lt;li&gt;Enter key password for &lt;code&gt;&amp;lt;my-key-alias&amp;gt;&lt;/code&gt;: You can press Enter to use the same password as the keystore password or you can create a separate, unique password. This is your &lt;strong&gt;Key Password&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You'll get an output similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Generating 2,048 bit RSA key pair and self-signed certificate (SHA384withRSA) with a validity of 10,000 days
    for: CN=Norman Osborn, OU=Research &amp;amp; Development, O=Oscorp, L=New York, ST=New York, C=US
[Storing goblin.jks]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;IMPORTANT: Store this file somewhere safe! It is used to sign every version of your app. If it is lost, you will not be able to update your app. If you have multiple apps, you should generate a new keystore file for each application.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Configure NativePHP
&lt;/h2&gt;

&lt;p&gt;Now that you've got a keystore file (with your signing key inside it), we need to configure NativePHP to use it whenever you build a &lt;strong&gt;bundle&lt;/strong&gt; version of your app.&lt;/p&gt;

&lt;p&gt;There are several ways you can configure NativePHP to use this. If you're just building on your local machine the easiest is to place the following keys in your &lt;code&gt;.env&lt;/code&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ANDROID_KEYSTORE_FILE=/Users/normanosborn/dev/goblin-app/goblin.jks
ANDROID_KEYSTORE_PASSWORD=your-keystore-password-from-earlier
ANDROID_KEY_ALIAS=your-key-alias-from-earlier
ANDROID_KEY_PASSWORD=your-key-password-from-earlier
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Then build your application
npm run build &amp;amp;&amp;amp; php artisan native:package android --build-type=bundle
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you're using some sort of automation (CI/CD perhaps), you can pass the same values as parameters to the &lt;code&gt;native:package&lt;/code&gt; command.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;php artisan native:package android \
  --build-type=bundle \
  --keystore=/Users/normanosborn/dev/goblin-app/goblin.jks \
  --keystore-password=your-keystore-password-from-earlier \
  --key-alias=your-key-alias-from-earlier \
  --key-password=your-key-password-from-earlier \
  --output=./artifacts \
  --no-tty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;or as environment variables&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export ANDROID_KEYSTORE_FILE="Users/normanosborn/dev/goblin-app/goblin.jks"
export ANDROID_KEYSTORE_PASSWORD="your-keystore-password-from-earlier"
export ANDROID_KEY_ALIAS="your-key-alias-from-earlier"
export ANDROID_KEY_PASSWORD="your-key-password-from-earlier"

php artisan native:package android --build-type=bundle --output=./artifacts --no-tty
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Please check out the &lt;a href="https://nativephp.com/docs/mobile/1/concepts/ci-cd" rel="noopener noreferrer"&gt;NativePHP docs&lt;/a&gt; for the latest info on this.&lt;/p&gt;

&lt;h2&gt;
  
  
  Publish App
&lt;/h2&gt;

&lt;p&gt;Once you've run the &lt;code&gt;native:package&lt;/code&gt; command, a window will pop up to the folder where your &lt;code&gt;.aab&lt;/code&gt; file is stored. This is your bundled and signed Android application which you can &lt;a href="https://support.google.com/googleplay/android-developer/answer/9859152" rel="noopener noreferrer"&gt;upload to the Google Play Console&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Once you know, it's pretty straight-forward to build and publish your application but I'm just new to this and there may be some things that I've missed. So I will update this article as I learn more.&lt;/p&gt;

</description>
      <category>nativephp</category>
      <category>php</category>
      <category>laravel</category>
      <category>android</category>
    </item>
    <item>
      <title>Don't expose your database to the world</title>
      <dc:creator>Michael Ishri</dc:creator>
      <pubDate>Fri, 04 Jul 2025 04:10:22 +0000</pubDate>
      <link>https://forem.com/michaelishri/dont-expose-your-database-to-the-world-3fke</link>
      <guid>https://forem.com/michaelishri/dont-expose-your-database-to-the-world-3fke</guid>
      <description>&lt;p&gt;I'm so excited. I explored &lt;a href="https://nativephp.com/" rel="noopener noreferrer"&gt;NativePHP&lt;/a&gt; when I first heard about it for the desktop but I didn't really have a need for it at the time. I had a few ideas but nothing I was sure I wanted to spend a heap of time building. But when they announced support for iOS I was intrigued, then they quickly followed with Android support. I was in!&lt;/p&gt;

&lt;p&gt;I would consider myself a hobbyist, Laravel developer. I work for a large enterprise that is crusty and old and has no interest in modern tooling, so I'm stuck with what they dictate, so Laravel is just a thing I do out of interest. Having said that, I've worked in enterprise environments for a long time and understand a bunch about good architecture / practices.&lt;/p&gt;

&lt;p&gt;I forget that sometimes. That not everyone has my experience. So this post is for those that are exploring NativePHP on mobile and think that they need to connect their mobile application directly to a MySQL/Postgres database. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Short answer, please don't!&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;When you're developing a "regular" Laravel web application, your application will typically get deployed onto a web server which has a direct (and reliable) connection to your database server / service. Since your web server is considered a "secure" server, it is fine to have your database credentials somewhere your application can read from and use. Essentially it's a closed loop between your web server and database server.&lt;/p&gt;

&lt;p&gt;Database connections are typically stateful connections, meaning you connect to the server with your credentials then a session is established without having to re-authenticate again on subsequent operations. The network protocol to talk to your database server (engine) is designed to work in this way. Stateful connections are more sensitive to packet loss and are typically "heavier" than stateless connections (like HTTP). This is because both the client and server need to maintain the sessions, instead of closing the connection after the response has been sent (like in stateless connections). So the trade-off is usually speed (stateful) vs resilience (stateless).&lt;/p&gt;

&lt;p&gt;There is an exception to that speed argument when using a stateful connection model on unstable networks (such as mobile networks). Since there's overhead when re-establishing sessions.&lt;/p&gt;

&lt;p&gt;Having said all that, PHP is slightly different, because every request is a new request. In PHP, a new connection to the database is established for each web request, so even though the connection remains stateful, it is short-lived...typically (we could veer off here and discuss connection pooling and persistence, but those topics are for another day). This is probably why you don't run into connection limit issues (too many connections to the database server), because PHP will release/close the connection gracefully.&lt;/p&gt;

&lt;p&gt;When building you NativePHP mobile application, you can't guarantee a safe, secure, reliable environment (if it's being distributed publicly). So you should have a layer of abstraction in-between your application and the database server. When working with Laravel, this would usually be a REST API.&lt;/p&gt;

&lt;p&gt;So essentially, you would build REST API endpoints which require authentication, that return JSON to mobile application which is then consumed by your application.&lt;/p&gt;

&lt;p&gt;From a user flow perspective,&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The user installs your application&lt;/li&gt;
&lt;li&gt;The user provides their credentials to log into your application&lt;/li&gt;
&lt;li&gt;After successful auth, an API token is generated and sent to the user's device and stored securely on the device&lt;/li&gt;
&lt;li&gt;This API token is then used under-the-hood to interact with your API&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This means you don't need to expose your database to the outside world. You continue to just expose HTTP to the outside world which is easy to secure. You can easily set up key rotation on the server side (if you want to automatically expire the API token after a period of time). It's a stateless connection so able to recover on flaky connections plus a whole bunch of other benefits.&lt;/p&gt;

&lt;p&gt;This API token approach is just one way to handle this, there are other ways such as using JWT's, but in my opinion, when working with Laravel, this is the simplest. Check out the &lt;a href="https://laravel.com/docs/master/sanctum" rel="noopener noreferrer"&gt;Laravel Sanctum&lt;/a&gt; docs to understand how to implement this in your application.&lt;/p&gt;

&lt;p&gt;If we didn't take this approach, let's quickly imagine what could happen. &lt;/p&gt;

&lt;p&gt;You would need to figure out a way to store your database credentials on the client device. Just putting this in writing is making me scared...It's just a bad idea. We can't assume the client device is secure or will remain secure. We don't want hundreds of users making direct connections to your database server with the same credentials. If those credentials are compromised, then your database could get leaked. Since everyone would be using the same credentials, then everyone would have access to everyone else's information and because it's a direct connection to the database, it means your database would need to be exposed to the outside world. Once you have those credentials, you can just open MySQL workbench and start running arbitrary SQL queries. There are just too many issues to list with this scenario.&lt;/p&gt;

&lt;p&gt;So then lets assume you have some way of creating a new user account on the database server for each user of your application. You would still need to expose your database server to the outside world and if your user figures out their credentials to their database user, they could then again use MySQL workbench to just run arbitrary SQL queries. Let's hope you've set up the correct access levels for your user. You would need to implement row level access which is extremely granular and again, this whole thing is just a bad idea.&lt;/p&gt;

&lt;p&gt;The thing is, Laravel just makes building and securing API's so easy, there's little reason to not use it. I can only think of one example where you would need to store your database credentials in the client application. If you were building a database management tool like TablePlus and you wanted to have an "auto-login" feature for your user. That's it really.&lt;/p&gt;

&lt;p&gt;So, please don't expose your database server to the outside world. Keep it behind a secure network and use a REST API instead. Have authentication on your API and only send data your application needs, nothing more (avoid sending internal ID's, timestamps, sensitive data, etc).&lt;/p&gt;

</description>
      <category>nativephp</category>
      <category>mobile</category>
      <category>php</category>
    </item>
    <item>
      <title>Initial Commit</title>
      <dc:creator>Michael Ishri</dc:creator>
      <pubDate>Fri, 04 Jul 2025 02:32:24 +0000</pubDate>
      <link>https://forem.com/michaelishri/initial-commit-g70</link>
      <guid>https://forem.com/michaelishri/initial-commit-g70</guid>
      <description>&lt;p&gt;I'm new to this.&lt;/p&gt;

&lt;p&gt;I'm not new to the tech industry or to knowledge sharing or even documenting my experiences. In fact, I've been working in tech over 20 years now, but I am new to sharing my experiences publicly. I've always wanted to but have always felt that maybe I wouldn't have anything interesting to share or that I wouldn't be able to find the time to be consistently sharing so why bother starting. &lt;/p&gt;

&lt;p&gt;But I just need to start, today, right now!&lt;/p&gt;

&lt;p&gt;So here I am, I've started. Stay tuned for more.&lt;/p&gt;

</description>
      <category>introduction</category>
      <category>justme</category>
    </item>
  </channel>
</rss>
