تماشای این درس نیاز به اشتراک حرفه‌ای دارد.

NativePHP iOS Overview0:00

We're just gonna take a few minutes now to dive a little bit deeper, and we're gonna have a look at some of what's going on under the hood in native PHP. For mobile particularly, we'll focus on iOS, but principally it's exactly the same for Android, even though the implementation is quite different. For this, I'm gonna use Teal Draw because I'm gonna be talking about things and I'll be moving my hands around a lot,

because I'm gonna be talking about things and I'll be moving my hands around a lot, and it will be very non-visual if I don't. So this will hopefully help you get some of the concepts of what I'm talking about a little bit easier. Before I start drawing any diagrams though, the first thing I wanna do is look at some of the code. I'm just gonna scratch the surface. There's a lot more to look into, but let's build up a picture of this as we go through it.

There's a lot more to look into, but let's build up a picture of this as we go through it. NativePHP for iOS is a very typical Swift application. It's made up of a few Swift files. There's a basic Swift UI approach to building a user interface, although it's very simplified because there's basically just a web view and there's a lot of support stuff going on. Most of that lives in this native PHP project folder.

and there's a lot of support stuff going on. Most of that lives in this native PHP project folder. This is where all you'll see lots and lots of swift files, and this is what gets compiled into the final application. So everything in here is what makes up the application. Adjacent to that, there's also a bunch of external libraries, and we have to build these for each platform, so we build them for iPhone.

Embedded PHP Binary1:41

and we have to build these for each platform, so we build them for iPhone. Now, sublime doesn't show us those, so let's have a look at them in the finder. So we will go to native PHP, iOS libraries, iPhone os. These are all of the extensions that are needed to run PHP on a phone. And you can see the most important and biggest one of these is PHP itself.

And you can see the most important and biggest one of these is PHP itself. This is a statically compiled binary where PHP has been compiled in what's known as the embed sappi. The embed SAPPI means that this is configured to run inside another C application, and that means that we can embed it into a C application or a C like application and interact with PHP as if it's part of

or a C like application and interact with PHP as if it's part of that application rather than it being an external process running somewhere else. The embed sappy was originally meant for running PHP inside of web servers written in C like Apache, but we've turned it around and compiled it for iPhone and Android to make it work as part of those applications. And that's completely legitimate thing to do. PHP is built to do exactly this kind of thing.

And that's completely legitimate thing to do. PHP is built to do exactly this kind of thing. That's not to say that it was built to be compiled for an iPhone or for an Android phone. It really wasn't, but we managed to figure out how to make that work. And so we've compiled PHP for these devices. Inside of that PHP, we've also compiled our own custom extension, and the custom extension is what exposes the functions

Userland Facade Wrappers3:23

we've also compiled our own custom extension, and the custom extension is what exposes the functions that make all of the native functionality available to you. Let's have a look at how some of that works. Once we've installed it, it lives under the native PHP mobile folder, and here we can see all of the facades and classes that we have available. So let's have a look at one of the ones that we've been using.

So let's have a look at one of the ones that we've been using. So the dialogue alert function, and you can see that this NEAT class really is just a wrapper for a function that doesn't exist in PHP ordinarily, but what we've created in our native PHP extension and that function accepts these parameters. Why are we just wrapping these functions like this? Well, it gives us a nice class-based API without having

Why are we just wrapping these functions like this? Well, it gives us a nice class-based API without having to write class-based APIs in a C extension, which isn't that complicated, but it just adds a little bit of overhead to everything that we have to do. So we've got nice clean functions that are just built into the core of PHP, and then we wrap them in user land classes, and that gives us some flexibility

and then we wrap them in user land classes, and that gives us some flexibility so we can change the underlying function parameters and signatures without affecting the user land behavior, and we can add more functionality in here in in the future if we want to without having to recompile the entire PHP stack to give that to you. So for example, we may end up at some point with some lower level primitives that can be used across multiple functions in different

with some lower level primitives that can be used across multiple functions in different ways, and then in the user land code that we've got here in our package, it just taps into those underlying functions and adds functionality around it to make the developer experience really great. And from your point of view, you won't have to change anything about how your code works. We spend a lot of time thinking really hard about

Swift Entry Point Setup5:22

to change anything about how your code works. We spend a lot of time thinking really hard about how this should be structured and built to make it flexible and reliable, and so that it's gonna stand the test of time through multiple iterations and all of the different applications that you might be building with it. So if you're not familiar with SWIFT applications, the entry point is basically the one that's been named the same as the app.

the entry point is basically the one that's been named the same as the app. So it's this native PHP app, swift this struck, and this a knit function here in particular is what basically sets everything up so that we can run PHP inside of a Swift application. And there's lots of stuff that goes on here to make sure that it's all operating correctly and the way that you would expect for your Laravel application to be able to make requests

and the way that you would expect for your Laravel application to be able to make requests and do the things that you want to do. We won't go too deep, but there are some really key things that I want to cover. The first thing that happens once the application is finished, all of its boot up stuff, it sets up a web view, and the web view is configured in a way that when a request comes in for PHP, it will know how to handle it.

WebView Scheme Handler6:30

that when a request comes in for PHP, it will know how to handle it. Let's have a quick look at that. The web view is created in the content view class, and it's a very complex web view for a Swift application, and that's because it's having to create an environment that knows how to respond specifically to the requests that we wanna make for PHP and pass them off to the PHP engine. And to do that, we use something called

and pass them off to the PHP engine. And to do that, we use something called a custom scheme handler. What's a scheme? A scheme is the HTTP or HTTP S or FTP or there's a bunch of others. So a custom one is just our own custom, one of those. Is this the same as what you might have seen around deep links and that kind of thing? Yes and no. So deep links for your application allow your application

Yes and no. So deep links for your application allow your application to define a custom scheme handler for the operating system that it's running on. And so when any links use that scheme, it will open your application. This custom scheme is our custom scheme for native PHP internally to your application for this specific web view, it allows us to handle requests in that web view slightly differently.

for this specific web view, it allows us to handle requests in that web view slightly differently. So the custom scheme is called PHP, and we have this custom scheme handler, which knows how to interpret requests from the web view and pass them to the PHP engine and then handle the PHP engine's response and pass the final output back to the web view. In a sense, this is acting like a web server. It's not a web server.

In a sense, this is acting like a web server. It's not a web server. It doesn't have all of the extras that a web server has stuff to manage multiple connections to terminate TLS and all of that kind of stuff because we don't need it. We've got one connection, we've got one user at a time, and so we only really generally need to manage one request at a time. And this is great at that. It's really fast because there's no network involved

And this is great at that. It's really fast because there's no network involved and the PHP engine itself is exceptionally efficient. Then we layer on top of that Laravel and Laravel is very fast. So your applications end up being really, really performant just because all of these pieces are already very good and there's no network involved. It's really fantastic

and there's no network involved. It's really fantastic and it kind of feels magical to see all of this come together. Let's go through some of the principles of how this is working. We set up this scheme handler to run on a queue, and that means that we can control how much work it's able to do at once. That's important because we can only have one

how much work it's able to do at once. That's important because we can only have one PHP engine running at a time. Whilst PHP can run in multiple processes quite safely on a normal server on the mobile devices, it's got limited resources. Most modern mobile devices are pretty powerful, and so they can support multiple threads within an application. So there's some work that we'd have to do

threads within an application. So there's some work that we'd have to do to make PHP thread safe in this environment, but for now, this works really well where we've just got one PHP thread running whenever we need it, and we run it and close it down all as part of a single request. And this is great because PHPs model has always been this shared nothing, which is a very, very memory safe approach. We give PHP a certain amount of memory, we fill it up with stuff, and at the end

We give PHP a certain amount of memory, we fill it up with stuff, and at the end of the request we get rid of it all. So we know that we are never gonna use more memory than PHP allows us to have, and that's really great for our applications. Generally speaking, we know that it's never gonna use more memory than we allow PHP to have. So that means that your applications built for iPhone

allow PHP to have. So that means that your applications built for iPhone and Android are gonna be some of the best applications on the user's device because there's less chance that it's going to eat up the phone's memory and CPU cycles. Certainly not because of PHP anyway, reading through this code, and we're not gonna read through all of it because there's a lot of it. But if you take the time to have a a look through

of it because there's a lot of it. But if you take the time to have a a look through and understand what's going on here, you'll see that it looks very familiar. We have this kind of request response cycle just like you would have in a typical PHP application, and we're taking all of that data from the request, pushing it through the PHP engine, and that's gonna run our Laravel application. Laravel sees it as just a normal web request, does

and that's gonna run our Laravel application. Laravel sees it as just a normal web request, does what it does, and then we handle the response into the web view. So everything feels just like you're interacting with a web server, but you're not. You're interacting with the application that's running around your PHP code. And then obviously because it's running your PHP code, it runs those functions that we've got in the package.

And then obviously because it's running your PHP code, it runs those functions that we've got in the package. So when those functions run, then it taps into the native functionality. Now that's the bit of magic that happens inside the extension. So our C extension receives those PHP function calls and it turns them into native function calls. And it does that very simply because PHP is written in sea,

And it does that very simply because PHP is written in sea, they're already native function calls. All we have to do is map those functions over to functions that exist in Swift. So we can have a look at one of those here in the bridge. So let's see the other side of our alert. This is it. This is the SWIFT code that handles our alert function call when the alert function gets called.

that handles our alert function call when the alert function gets called. This is what runs PHP is basically doing very little, it's just varying along the data. The actual application code is native application code. So in a very real sense, this is native PHP and that's fantastic. It means that we get native performance in all of the UI things that we want to do that are outside of the web view.

of the UI things that we want to do that are outside of the web view. We can tap into all of those local APIs and we can do some really, really cool things. Let's just diagram the things that we've been talking about. So let's go back to TL Draw. We have our application and then inside our application we have a PHP engine. Inside PHP, we have our extension. Inside our application, we have a web view.

Inside PHP, we have our extension. Inside our application, we have a web view. When our application boots, one of the first thing that happens is we tell the web view to go to the home URL. That's PHP 1, 2, 7, 0 0 1. Now that looks like a URL that's gonna try to hit a server, but trust me, it's not. The web view sees this and it knows to interpret it in a very special way, the web view makes a request To PHP,

and it knows to interpret it in a very special way, the web view makes a request To PHP, and then PHP runs and handles that request and returns the response to the web view. And that is it. It's pretty much that simple. The only extra thing to happen is if the request contains a function call to one of our native functions, the PHP engine is gonna execute that function, which exists in our extension, and then that function is gonna call into our application

that function, which exists in our extension, and then that function is gonna call into our application somewhere in here. And then the result of that function gets passed back through PHP through our extension back, Back to the handler and back to the web view. There's no beating around the bush. There are more layers here and it will cause the application to be slightly slower, but really that translates to almost nothing.

and it will cause the application to be slightly slower, but really that translates to almost nothing. It's imperceptible from the user's perspective. And so your applications still feel really native. And with the fact that we are using a web view means that you can build your UI exactly the way that you want to. So you have ultimate flexibility with the trade off, slightly less performance, and you can still use native components two. Now the extra cool layer comes in here.

Event System and Livewire Demo15:26

and you can still use native components two. Now the extra cool layer comes in here. What we devised is an event system where we tell the native UI components what we want to happen when they have finished doing their work. And the thing that we have them do is fire an event. And we do that through this event bridge. And the events are just, uh, well, you can see this looks like a PHP class name. And then we've got some values being passed to it.

you can see this looks like a PHP class name. And then we've got some values being passed to it. That's exactly what they are. Let's have a look at one of these events. They're in the PHP code in our extension. So we'll look at this alert event and you'll see it's called button pressed, just exactly like this is here. This has some huge benefits for how we think about how we're handling the native UI interactions.

This has some huge benefits for how we think about how we're handling the native UI interactions. We can define our reactive behavior to those components in PHP, and we can handle the events coming from them either in PHP or JavaScript. And that lets us do some really, really cool things. Let's put some of this into practice. Let's go back to our hello world component for a second now. And let me just make sure

Let's go back to our hello world component for a second now. And let me just make sure that we've got our simulator running and we've got our hot reloading still going. Great. When we show this alert, let's say we want to do something. When the button is pressed, I want it to do a login. This isn't a particularly good way of doing this, but it's a quick demonstration of what we're talking about. So let's just play through what we want to happen.

but it's a quick demonstration of what we're talking about. So let's just play through what we want to happen. First of all, I want to set the token that's done. Then I want to get the token. And once I've got the token, I want to log the user in. So once I hit that okay button, I want it to be treated as though the user's logged in. How do we do that? Well, because of our event system, we can actually listen for this event in this livewire component using a

because of our event system, we can actually listen for this event in this livewire component using a very handy feature. And that's live wire's on attribute. We'll import that with the on attribute. We can tell it to listen for a specific front end event. So in this case, we prefix these with the word native and a colon. So that will listen for our specific JavaScript event that's happening on the livewire front end side.

So that will listen for our specific JavaScript event that's happening on the livewire front end side. And it's gonna pass that to the backend and run our function. And because we're defining it through this on attribute, Livewire knows which function to call. So all we need to do is tell it to use the button pressed event so we can give it the class name like this. That's it for this. I just need to import that event.

so we can give it the class name like this. That's it for this. I just need to import that event. Great. And then we need to decide what to do for this demo. I'm just going to set a value to say this logged in equals true, and we need to set that up here. So I'm going to give, make a public logged in and we'll set it to false. And then in our view, we just need to show some different ui. Remember, this is all the way that livewire works.

to show some different ui. Remember, this is all the way that livewire works. By default, when we update the state on the server or the backend in this case, 'cause it's not a server, the view will get updated with the changes that we make. So let's just add a simple check for our logged in state. So if logged in, then we're going to, we'll put it in a a div and we'll give this some nice styles.

then we're going to, we'll put it in a a div and we'll give this some nice styles. So we'll say text XXL, and we'll make it text red and we'll say, yay, you are logged in with a ta. And then if we go to our simulator, now when we get the token, we get our token, but when we press, okay, it should update the page to say that we are logged in.

but when we press, okay, it should update the page to say that we are logged in. Okay, it didn't work. But that leads us down a path to investigation. And that's good. I've made a mistake somewhere, but I'm not gonna try and hunt it out on my own. We are gonna find it together. I'm gonna open a new tab. And in order to debug some of this stuff, it's really helpful to run our application with the debugging on.

Debugging in Xcode20:21

it's really helpful to run our application with the debugging on. And we can't do that in the terminal directly at the moment, but what we can do is run it in X code for an iOS application. So I'm gonna do that. So we're gonna native open iOS X code is a crazy piece of software. And if you're not used to it, there's a lot here that certainly overwhelms you. It certainly did for me.

that certainly overwhelms you. It certainly did for me. And so I don't really want to spend a lot of time at all in Xcode. I want to do everything in the tools that I'm already familiar with PHP in Laravel. So I don't really like coming into Xcode, but I do spend a lot of time here at the moment whilst in building all of this stuff, the most important thing here is

of time here at the moment whilst in building all of this stuff, the most important thing here is that I'm coming to just run my application from Xcode so that I can do debugging. And to get to that place, we need to just change a few things. First of all, up here in the top bar, you'll see there are schemes. One is just called native PHP and one is called native PHP simulator.

One is just called native PHP and one is called native PHP simulator. Now, it should be obvious, the simulator one will run on a simulator, native PHP won't. These two are built for different environments. This one's built for real devices and this one's built for simulators. And yes, they are different and it has to be done that way. So we wanna be on the NATO PHP simulator one, and then we need to select the simulator device.

So we wanna be on the NATO PHP simulator one, and then we need to select the simulator device. I don't wanna run it on a real device 'cause we just said that won't work. So I want to go back to the iPhone 16 running the latest version of iOS. And that's this one, which actually doesn't have the version number weirdly. So I wanna select that.

number weirdly. So I wanna select that. And that's going to run this on our simulator. Now we're already running this application on our simulator. True, but what we're gonna do now is run it with all of the debug symbols in place, which allows for Xcode to receive output from the application. So if we run this, we can go to the console here for this run, and we'll start to see all of the output

the console here for this run, and we'll start to see all of the output that comes from the application. We should then be able to debug what's going wrong. Call the builder successful, it's gonna open the app. Yeah. And now we start to see the debug output. Excellent. So we should be able to see at some point where the error is. Remember that's what we're focusing on here. We want to get back to the place that we're at so

Remember that's what we're focusing on here. We want to get back to the place that we're at so that we can see the error. So now our application is running with all of the debugging, and if we'd attach to it in the console, we can hopefully press this button and see what's the error when we press our alert button and try and discover what's gone wrong. So look out for it in this one. Well, okay, let's just work backwards.

So look out for it in this one. Well, okay, let's just work backwards. What's happening here? It's saying there's a event that was dispatched successfully. So this is the event firing and the request that's going to PHP at a special endpoint for handling these events, which means that the JavaScript to receive the event, it probably means that Livewire received the event. But yeah, it definitely did.

that Livewire received the event. But yeah, it definitely did. There's no obvious error here, but I can see what's wrong. I think I've put the wrong code somewhere around this event name. So we should be looking for this event. This is the event that's been dispatched, native mobile events, alert button pressed. So let's just go back and have a look at our class and make sure that's correct.

So let's just go back and have a look at our class and make sure that's correct. And no, I typed the wrong name. So it's actually dialogue and it should have been alert. Now, I'll save this. It's gonna try and refresh the view in the simulator, but I don't think this is gonna work still because basically when you're debugging applications, hot reloading doesn't work at all. I'm gonna stop debugging. We can come out of here.

hot reloading doesn't work at all. I'm gonna stop debugging. We can come out of here. I think I've fixed that issue. We'll reboot the application and then hopefully our hot reloading will still work. Yay. We are logged in. So that's a fundamental piece of the whole puzzle of how all of this stuff works. When we're hitting our native UI components, they will often be asynchronous,

When we're hitting our native UI components, they will often be asynchronous, and that means that we have to wait for the user to do something before we can carry on what we're doing. And that means that PHP state is gonna be completely wiped away, and then we're gonna receive an event with some data potentially, and we have to handle that, and we might need to bring some state back from somewhere else. Livewire is great for this

back from somewhere else. Livewire is great for this because it maintains an internal sense of state for us across multiple requests. Other front end libraries are gonna be great at this too. If you use and react or view or felt or anything similar to that where state is kind of kept on the front end, that's gonna be great because it's gonna allow you to push all of that state to the backend every time you make a request.

because it's gonna allow you to push all of that state to the backend every time you make a request. So that's something that's really critical for making these applications work and feel like they behave like a native application. This obviously isn't a very secure login uh, approach, but you can hopefully see how you might use this to create the sense of interaction with multiple elements that then you can create complex scenarios for your application.

that then you can create complex scenarios for your application. The camera is camera's. Another good example, when you take a photo and the the user says, this is the one that I want to use. Once they've finished with the camera sheet, then the event fires that tells your application, this is the image that they've captured. And yes, eventually we'll get to all of those native functions

Performance and App Size26:31

And yes, eventually we'll get to all of those native functions and even allowing you to expand on the capabilities of the framework. But right now we've got quite a limited set of features and we've got a few more features that we really need to build out in order to make robust and performant applications. One of the things that we're focusing heavily on at the moment is performance, and that's both the size

One of the things that we're focusing heavily on at the moment is performance, and that's both the size and speed issue. So we've worked really hard to bring the size of these applications down. Bundling PHP in with your application is going to bloat it. There's no two ways about it. We're using the systems built in web use, which is great. And really aside of a few bits

We're using the systems built in web use, which is great. And really aside of a few bits of just passing information along, native PHP isn't doing very much at all. It's almost all coordination of how to get your application into the native environment and then just allow it to make use of the features that it has. This approach. As I said at the beginning, basically the same for both iOS and Android.

This approach. As I said at the beginning, basically the same for both iOS and Android. And the only ways that it really differs are that on iOS we have to compile this fully static build of PHP. We can't link anything dynamically in our applications. And I don't wanna get into all of the details of that, but it just means that the PHP engine is a little bit bigger on iOS than it is on Android. And on Android you can use dynamically linked libraries,

on iOS than it is on Android. And on Android you can use dynamically linked libraries, and that does make the Android applications just that touch smaller than the iPhone applications. But in any case, these applications are still very small. We're not talking about hundreds and hundreds of megabytes, and we're always working to try and trim down the size of your applications. I'm sure there's still a long way that we can go. So with every update,

I'm sure there's still a long way that we can go. So with every update, expect various improvements in both the size and speed of your applications. In the next lesson, we're gonna run through really high level how you would then publish your applications to the stores.

دوست دارید گاهی خبرهای Laracasts را ایمیل کنیم؟