How Expo Modules Simplify React Native Development - Tomasz Sapeta | React Native Heroes 2023

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
so far I mentioned four different languages and used many words that you need to know and be aware of to make things easier let Expo do this job for you and reduce the number of things that you need to care about to make the maintenance easier and let the community iterate faster we decided to create a model system that reduces the costs and Technical depth to a minimum [Music] so hello everyone um so sometimes we come across of the need to use some native apis uh or like third party libraries in our native applications but sometimes there is no such Library available yet or um like all of them are of poor quality or or even worse unmaintained which is right now unfortunately pretty common so today I'm going to talk a little bit about Native moduls uh why creating and maintaining them might be hard and challenging and how Expo can help you in this process but first let me introduce myself uh I'm thas I work at software menion uh as a tech lead of uh the Expo SDK uh Team I usually work on the core parts of of Expo but also created and Main contain a bunch of Express DK libraries and yeah you can find me on Twitter and this handle at soft mention is a software agency based in kakow in Poland uh with almost 200 developers already and we've been using rck native uh for our clients projects uh since the very beginning um we contribute to its development and are authors of um the most popular open source libraries for R native such as rock native gesture Handler reanimated screens and also co-authors of rock navigation and Expo at the beginning of this year um my company organized a state of rag native survey so there was also a question that we asked the responders uh what were the backgrounds before they started started using Ro native that was a multiple choice question and like front end here means something other than react so it might be some confusion uh like why react is like bigger than front end but yeah it's the other ones and it's clear that the largest group here uh consists of web developers who already have some experience with JavaScript but what is important for this group of people who just started programming uh to write a native modules eily if you can write native modules in JavaScript but we can't since JavaScript is not the native language on mobile platforms as opposed to the browsers no doubts the most important things are an easy way uh to bootstrap a module having a good documentation model and accessible language with a large amount of online resources resources so we can learn a new language um and platform faster and the other group of mobile and desktop developers uh is much smaller you would ask why so some mobile Developers say that R native is not truly native and so would rather keep doing native to deny it and convince them to migrate R native writing native modules um and Views should be as easy as it is right now in Native mobile apps at least for for for these developers and right now to migrate a native app to work native like it would be I think the best if you can just reuse the existing logic and only add a connecting P so that this logic native logic can be like exported to JavaScript but this logic can sometimes be really complex and the native model system needs to be capable of reflecting uh like this complex Logic on the native side on the JavaScript side let's create a r native library and see what we can do by like we can do this by running this command and this will set up a library and also an example app where we can try things out and here is the the structure of the folder created by this script and we'll quickly go through some of those files so the module created simply multiplies two numbers um here is the implementation in Java for Android and we specify um like what the the module name is and Implement a multiply function uh with r method annotation we also need a specification class it's for the new architecture basically and this specific needs to extend the native turbo model compat spec uh which is code generated so it doesn't really mean too much and for compatibility reasons we also have got another specification but this time with the method declaration as well so it might be a little bit confusing that we have we have to support two architectures at the same time we have like very similar classes for each of the architecture um I think it's it's not that easy to to handle everything and on iOS we have also two files the first one is a header uh and to support more architectures we also need to use the prosess or directive um to use different interface uh depending on the architecture and in the implementation file we need to export the model and um its methods using macros and for the new architecture we need to include another method uh which mixes Objective C and C++ so basically this file is in objective C++ and on the JS side we have even more code that should probably be extracted to the core um I would say it's kind of a boilerplate code here and additionally we need a specification in typescript um that will be used by Cod gen to generate native specifications that I showed before uh for for Android and to sum up there is a lot of code just for a simple module that multiplies two numbers and another way to write Aid native module is to directly use JSI JSI stands for JavaScript interface and generally not recommended uh to use and for it's more for advanced developers uh but I wanted to show you how it could look like as this is what librar such as ranimated rck native skia um or retive vision camera uh use so we have a C++ Lambda uh that is called a host function uh it receives a this value and all the arguments pass from JS and now we create a JS function from this host function and then we get the global object from the runtime to decorate it with our function well it's definitely much more powerful as you have full control directly on the JS values so we can mod modify them but here we don't have any arguments types validations and also calling it asynchronously would require us to write even more and more complex code so far I mentioned four different languages and used many words that you need to know and be aware of to make things easier let's let Expo do this job for you and reduce the number um of things that you need to care about let's replace those languages with more modern ones and let's stop thinking about the architectures and all those other scary words so in Expo our team needs to maintain a large set of libraries and maintaining native modules uh over time and in constantly changing environment is quite expensive I think we have like some somewhere around 70 packages in our monor repo so it's it's it's quite huge amount and we found out that existing re native API for Native modules is not scaling very well for us and it's giving us some additional overhead uh on many levels from onboarding new contributors uh to writing a lot of boiler plate code and to make the maintenance easier and let the community iterate faster we decided to create a modu system that reduces the costs and Technical depth to a minimum and one of the difficulties of writing your native models is context switching between the vastly different languages and paradigms for writing native models for each platform and due to the differences uh between those platforms it cannot be completely avoided but we feel they need to have just one common API and the documentation to simplify the development as much as possible to make it easier for a single developer to maintain a library on multiple platforms and at Expo and software mention we believe that the new architecture is the future of rag native so all Expo modules work work with the new architecture without adding any piece of C++ code and like all existing SD X SDK packages already support the new architecture without even checking like which architecture is used by the app and we want to not only build the powerful Expos dek libraries but also make them easy and more intuitive to use by app developers a native model that is just a flat object with a set of some functions is not enough in our opinion and for example to bring some web or node.js specifications to rock native uh the module needs to support things like Dynamic Properties or native classes otherwise we would have to write a lot of code on the JavaScript side just to try to make the API object object oriented from the flat like set of functions which is very very complicated you need to trust me and also who wants to write boilet codes let's get rid of it as much as possible I mentioned about the crossplatform API in domain specific language so we already know jsx in react it's a good example of the DSL syntax and also we have a Swifty y uh on iOS which is also another example that confirmed that as Mandalorian that this is the way to build a hierarchical data structure in a more maintainable and readable way and in this case it's a view hierarchy and the same approach was then adopted by jetpack compost for Android which also proves its crossplatform it let's review how we would write an expo module with the same functionality we can use the create Expo module command for that so here we have the modu in cotlin and like the modu definition over there is basically the DSL syntax that I mentioned and it's used as a source of Truth For What the module exports to JavaScript and so the module is exported under under my Expo module name uh with a constant and one assing function that multiplies those numbers now let's jump to Swift doesn't it look familiar it's almost the same and the differences are only on the language differences um like language specific level and on the JS side you only need to use requir native module with the name that we just use in our definition and that's it so let's go back to the native definition and I will be referring only to Swift uh since as you as you may saw already uh like the syntax is very similar but it would work like in the same way uh in cotlin except those language specific differences and now based on the module definition um the module object is then built on the JS site and installed in the global object under Expo modules namespace but here the problem is that this multiply function is an assing function so why do we need to well switch to a different threet and do this command asynchronously since it's like pretty fast and easy operation that doesn't have to be deferred to another threet so sometimes you also want like this assing function to run on the main threet which is also called UI threet like for example if you want to present a model or like do some modifications in the view hierarchy or whatever and to avoid crashes it has to be called from the main threet and you can use the runon Q modifier it also looks pretty similar to to what we do in Swifty Y and J compost to modify the component and this specific function has this weakness of of being an assing function so let's remove the ASN prefix uh and the function will immediately be exported as a synchronous function um without returning the promise and switching the threet moreover we can even go further and we can return another definition from the function so here we have a function that can prefetch something from like the given URL and you want to return a subscription that you can then abort from from JavaScript if you prefer properties over Getters and Setters we've got that covered as well so you can use a property component which basically maps to something that you can on JavaScript you can use object and Define property uh where you can Define dynamically what the property needs to return you can also use a custom Setter and so on right but validating and converting arguments from JavaScript to Native is also painful especially when it comes to dictionaries where each entry of the the dictionary needs to be validated and converted separately so we implemented a special structure that we call a record that can automatically do this for you so if you have written a native model before uh you've probably written called something like this this is not very good as for example um like if we look at the Quality variable uh we are not even sure if it's actually a number because in Objective C like all those entries in the dictionary are just a pointers to something um and because of the nature of objective c uh the dynamic nature it basically lets us assign a pointer to any type without even uh throwing any errors so if you want to validate those parameters uh it would take some more code so instead of using the type dictionary values you can write your own struct that will not only make it convenient to use but also perform validations automatically here is our record that provides some default values as well and we can refine this type even further because we know that the media types media types here yeah but the media types are like the the options that we can use is like images videos or all types of of of Medias so we can use another enum uh with all those cases and the enum only need to implement the enumerated protocol and now we switched the string uh to the media time inum which defaults to images option and now if someone passes something else than those cases then it will throw an error automatically so to summarize now in the functions body we have we are sure that the options are properly typed and validated it works per perfectly with auto completion in excode and Android studio and there is no chance that the typo will get unnoticed uh for optional Fields the default variabl already provided the function fails fails early uh in case of unexpected and it's easy to keep in sync with the equivalent uh type in typescript but native model is not only the native thing the other use case to dive into native code is to write a native react component so to export native view we only need two things this is the implementation of the platform specific View and the definition so the Expo view class basically inherits from UI view on iOS um and on Android it's a group View and to react to prop changes we can add a prop component uh to its definition specifying its type how the change should affect the view and here we also have an example that you can also use some other types as argument types so in this case it's a u UA color so whenever your user of your library passes like some lgba uh hex uh string or css named colors it will be automatically converted to the platform specific type such as UI color however the react component is not just props sometimes we need to call a function on the ref on the component so with expon you can do that but just adding a native uh function inside of the definition so let's imagine that we have a camera view and we want to take a picture uh from the current frame so of course we need a way to tell the view to take this picture but doing this through props doesn't sound like a good idea so we do such things using react refs since we interact with the UI all view functions must be asynchronous as they run on the main threet by default and typed AR are kind of like AR liked objects that provide a mechanism for reading and writing binary data in memory buffers so in JavaScript we have a few different types uh of typed arise depending on uh the element type and typed AR are very useful for manipulating on big row binary data um and using type Tera is much more efficient uh as they are optimized by JavaScript engines what's also important is that typed RIS are basically pointers to a buffer in a memory and the memory is then shared between JavaScript and Native so we can read and write directly to the same memory used by both environments and the most common use cases for typed RIS um are like some f that sometimes require some heavy work so it's for example audio video processing uh cryptography or some Network traffic optimizations in Bridge and turbo modules uh there is no easy way to use them as there are there is no built-in API to interact with them directly and as an example of the usage of typed Aris as a function um it's a function get random values which is defined by web crypto specification with typed R built in in the module API implementing that function iOS is just a few lines of code however it doesn't handle the case where the status means where this native function uh returns um an error status so let's check the status and return exception in this case so here is the exception that we throw from here and since we recommend separating the exceptions uh exception messages to separate classes so your codee code doesn't look like bloated with all those error messages so you make a separate class for for the exception and separate the the exception message from from the the code and to nicely handle errors we adopted the idea from java that is known as trainable exceptions so in my opinion it's pretty useful for debugging so you can immediately see what went wrong and from where the error comes from you can can see all the exceptions that we're thrown along the way down um so the root cause is always in the root uh root message in the error message another thing that was not possible so far um is mutating the JS objects and your native functions that you can pass to the native function and note that this must run on the JS threet since we operate and modify JavaScript value directly and if we expect that this function can only handle JavaScript objects and not just primitive values can replace the argument type to JavaScript object uh and the appropriate exception will be automatically thrown um if someone passes something else than JavaScript object all right time for something harder and so as I said to be able to fully Implement some web and nodejs specifications and make Library apis more intuitive and object oriented the native module needs to be capable of having an a way to to Define native classes and so here is an example of the file stream that could be defined and we have some code that runs as part of the JS Constructor and a right function that accepts strings that are streamed to the file at the given path and here you basically associate this JS class with another native class and the Base Class of this native class is called the shared object it basically allows us to associate a single ja object with a single native object so we can use them interchangeably and share some data between JS and Native and so each time we initialize this JS object the native implementation of the Constructor returns an instance of the Native object so like those objects are associated with with each other um and whenever you this GS object to another native function you will get an instance of its Associated native class and for those of you who used ranimated you're probably familiar with the concept of shared values generally speaking shared values from ranimated work in the similar way but they point to A Primitive value not an object it's much more powerful than what for animated implemented and another feature of Expo modules are upd delegate subscribers so on iOS we usually have to we have a singl object called upd delegate and the setup instructions for some libraries um often include instructions to like copy some code into your app data gate if they need to respond to some platform events such as inbound links notifications or foreground and like foregrounding backgrounding the app and to simplify and automate the setup we've made a mechanism called upd delegate subscribers that allows your library to subscribe to calls uh to the Singleton appdelegate functions so in order for this to work the apps app delegate must only inherit from Expo app delegate which forwards their calls to all the subscribers a good example of the library that uses uh export delegate subscribers is a rect native Google signin that needs to listen um for the event that is triggered when the URL is open from the app and this approach doesn't need any Expo config plugin uh which would require us to use use some rug access to uh to modify the code in the app delegates um which could break the behavior if for example multiple libraries want to hook into the same uh into the same method like everything that we built at Expo um all our products such as rag native Expo CLI and Expo SDK Expo models also work and can be used with any R native app let's talk about the future of Expo moduls so since our DSL uh looks like Swift UI and Jetpack compos it feels obvious to just build them in and Swift has some nice features that are not available um in UI kit which is the the implementation for for view hierarchies on iOS so CFT y would definitely enable some new possibilities for for our U native views and so far there are a few Expo modules that some other some people from the community build but they all we're embedding a single Swift UI view so this view like doesn't support children props so it cannot Nest other Swifty W views into your native Swifty wi view so this kind of problem so far and we want to solve this uh by even letting you to to build a nested uh hierarchy of Cy and compos views and here's where the new architecture comes in uh because it basically allows us to build this this thing it was not possible in the architecture so far so I'm really looking forward for for for the new architecture to to build this I'm also happy to announce that we are working on adding support for more platforms since right now you can only use iOS Android and of course web there are some SLE differences between iOS Mac OS and tvos especially in terms of the views and since the modules API is mostly an abstraction this platform differences can mostly be resolved in the core part of Expo modules uh so you then to have to care about this and as a bonus I believe some of the existing Expos DK packages will just start start working uh on these platforms out of the box okay another feature of the Shar objects that I already mentioned is something that we want to use to share the references between different libraries so let's let's imagine that we want to use an image picker and then render the resulted image so right now the image picker libraries um usually save the image to the file system return the puff to this file and then you pass this this URL puff to the image component which which needs to read this file again and then render it why not just pass a reference to the native like on iOS it would be UI image so we don't have to write and read from file system so with Shar objects it will be possible without even having a dependency between those two image libraries and it's not just about image Pier like in xpros DK we have all the media library uh this kind of camera roll um Al image manipulator it's like each manipulation that you use from Expo image manipulator uh is again saving this file to file system uh which is unnecessary especially if you want to run a few Transformations manipulations on on the image and since the core part um of Expo moduls is now stable we finally have some bandwidth to to work on some new libraries uh we've already built Expo image as a replacement for R native fast image which unfortunately became unmaintained we also have a pretty good native test coverage uh for for for the Expo modules API I think all of those like mechanism that you use for Native unit tests and also UI tests it would be I think nice thing to to all so make it public for for other uh Library developers to make writing native unit tests easier the documentation for the modules API is um already out there it doesn't contain everything that I mentioned today since some of the features will be released as table in Expo SDK 49 uh later this month you can also join us on our Expo developers server on Discord where you can find some help uh when you want to build some Expo modules uh and also give us some feedback and there is also dedicated creating Expo modules Channel where we are all eager to to help so thanks for listening does anybody have any questions [Applause]
Info
Channel: React Native Heroes
Views: 2,860
Rating: undefined out of 5
Keywords: expo modules, react native development, simplifying development, mobile app development, react native tutorial, software mansion, swift and kotlin, typescript mobile development, native modules in react, expo modules api, expo for developers, native app development, cross-platform development, javascript frameworks, react native expo, app development simplified, developer tools, coding tips, software engineering, application development, mobile coding
Id: jY3yxIetD_g
Channel Id: undefined
Length: 29min 44sec (1784 seconds)
Published: Fri May 17 2024
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.