We will learn how to install an Objective C library distributed via a CocoaPod into our project and expose its native api to our app. Specifically, we will cover how to immediately start working with the library even when a NativeScript plugin does not exist for it. Take for example Filestack, a really powerful file uploading api that provides an SDK written in JavaScript for the web, but also offers native SDK's for iOS and Android. Let's take a look at how to code right against this native iOS SDK.
[00:00] If we view the installation instructions, we'll see mention of CocoaPods. This is probably new to most web developers, but CocoaPods are like NPM for native Objective-C libraries. We can see that this references the Filestack CocoaPod.
[00:13] You can actually browse and search CocoaPods much like you could NPM. Let's search for Filestack. Let's just make sure we're using the latest version of the pod. You can actually see 035, the version reference in the documentation, but also FS Picker.
[00:27] This is a newer reimplementation. We can view its GitHub here. For this lesson, we'll use the latest development of this pod. Let's copy this pod line here. At the root of our project here, we're just going to add a folder.
[00:40] We're just going to call it NativeScript Filestack, and we'll add a platforms directory inside of that. This will be specifically for iOS. Lastly, we'll add a pod file so we can install that pod, and drop in this pod declaration.
[00:56] Next, let's add a filestack.ios.typescript file here to represent the API we're going to expose. We'll just export a class, Filestack. In our constructor, we'll code right against the Objective-C library. If we scroll down on the GitHub's README, we'll see some example Objective-C code. Let's copy and paste this as-is.
[01:20] Now, we just want to go through and convert this to JavaScript-like method calls. Let's create a local reference to hold onto our config. To convert this, we'll end up getting rid of the brackets, since the brackets are Objective-C syntax.
[01:35] Instead, we'll use the FSConfig class, which is going to call a method called allocate. We'll execute that like a JavaScript method call, and that will give us this initWithApiKey method. This @ symbol is just Objective-C's way of declaring a string. We can omit that, and just pass along a direct string here.
[01:56] Since there are no typings that ship with his library, we'll just declare this class at the top, and move onto the next line. How you choose to write a library and expose an API is completely up to you, and is certainly a case-by-case type of thing.
[02:11] I'm just going to create another local reference here to these storage options, and convert this line in the same way we did above. This FSStoreOptions will be the class. It's calling a method called allocate, and that gives us this init method.
[02:28] Then we'll just declare this class at the top. For this next line, we can see location is being set to a standalone reference, FS Store Location S3. Beware of these. Sometimes these will be exposed to NativeScript, and sometimes they won't.
[02:44] For these, I often find it easier and safer to actually grab its value from the library itself. If you go back to the GitHub repo, we can search for that value. If you do not see that value being defined, it's often that CocoaPod will reference another pod that actually defines that value.
[03:01] We can see that down here, this has a dependency on the Filestack. We can go into that repo, and search for the same value. Right away, we can see this define line that sets it as an S3 string. We can actually just use the raw string value instead of this static enumerable, and this will work just as well.
[03:24] We'll continue converting. This will reference our store options. Here, we'll just set a local variable, theme. That will be the FS Theme class that references the Filestack theme method. We'll declare this at the top.
[03:37] We have our controller here we'll define as another local variable. We'll remove the brackets. This will call this allocate method. This is where our conversion gets rather interesting. Objective-C has these parameterized method calls.
[03:53] When we convert this to NativeScript, we just want to collapse these parameters here. initWithConfig is the beginning of the function, and theme is the parameter for the next argument. We're going to take that out, and actually collapse it into the method call.
[04:10] That becomes initWithConfigTheme. Every time we collapse the parameterized method call into each other, we capitalize the first character in that parameter. Then everything else just becomes an argument passed to the method.
[04:26] It's very important that every time you combine a method in such a way that you pass these arguments in in the right order, as it's been collapsed. This, of course, is our reference to the config, and we'll just declare FSPickerController at the top.
[04:44] We're going to ignore handling delegates in this lesson, but let's go back to the code sample. This line right here, where that controller is actually presented in the view, we want to work with that.
[04:54] Whenever you're dealing with a reference to self in Objective-C, that's often referencing a standard UI view controller. In this case, we just want this view to show over the main view controller. We can take advantage of those TNS platform declarations that we have set up.
[05:09] We want to first get a reference to the app Window using UI application. We'll use the shared application instance, and grab key window. That will give us a reference to the root view controller.
[05:22] Then because we may want to reference this easily from other parts of the code, we'll just refactor that to a convenient constant function. We'll just call this root VC, we'll drop this here, and we'll just make sure that returns our instance here.
[05:34] Instead of using self here, we're going to use this root view controller to present the view controller. Because we have the typings installed, and it's using inference on TypeScript here, it will give us options of the Objective-C methods that we have.
[05:49] We'll find that there is one similar. You can see below, it was calling presentViewController. Then there's an animated param, and a completion param. You can see collapsed, this is exactly how that call would look -- presentViewController, then animated as the first param, and completion at the end.
[06:10] Then to pass our arguments in order, you can see the controller is the first argument. Animated is just a Boolean, and then for completion, we could add a callback function, but for now, we're just going to pass null. Then we can rid of this call, since we now are doing the same thing.
[06:28] Since this library requires an API key, we'll just make this a parameter we can pass in, API key here, which'll be a string. That way, when we use this library, we can just pass in the API key. We can register a free demo account to a get an API key here.
[06:42] Now, let's add a package file to define our internal plugin here. We'll give it a name, version, we'll specify the main to reference just Filestack, and we'll provide the NativeScript key, and for right now, just let NativeScript know that this supports iOS.
[06:56] If you were working against a specific version of NativeScript, you could specify that version here. Now, we are ready to compile our plugin using TSC.
[07:05] We'll reference the Filestack iOS, then we'll specify types to include our TNS platform declarations for iOS, and ensure the ES2016 lib is included. As an added nicety, we'll ensure that declarations are generated for our internal plugin.
[07:21] We can see the JavaScript that it generated, and the declaration file, which we're going to rename, and keep up with as index. Then we can reference that as the typings on our package here.
[07:33] That way, when we use the API, we will actually get IntelliSense on it. Now, we can install in the plugin using TNS plugin add, NativeScript Filestack. NativeScript will find it locally in your project, and add it to your package.
[07:45] Now, we can just use it. Let's open up our app component, and we can import directly from our internal plugin. We had a class called Filestack. Inside the components constructor, we'll just create an instance of this class.
[08:01] It accepts, of course, the API key. I'll just use one I had set up from a free demo account. If we look at the API we exposed, upon construction of this class, it should create this Filestack file picker, and present it automatically in the view.
[08:17] Now, let's run our project to check it out. You'll notice a CocoaPod error. Some CocoaPods you use may require a minimum deployment target. We can remedy this by checking what the target is from the pod spec file.
[08:33] If we go down through here, we can see that iOS has a deployment target of 8.4. Back in our pod file, we can actually just add that declaration here, that for iOS, we want to make sure that 8.4 is at least targeted.
[08:49] Since we changed the pod file, we want to make sure that that plugin is removed, and added back. We'll add a convenient script to our package that will ensure that our plugin gets built fresh every time, and removes and adds the plugin back.
[09:03] If we refer back to the command that we used to build our plugin, we'll just copy that. Then we'll add a TNS plugin remove, and ensure that it is properly added back. This will save us each time we run our project to make sure we get any latest changes we make to this internal plugin.
[09:20] Then we'll just add a convenient start script that will run that build, and then lastly, launch our app. Now, let's give our new script a shot. We'll see this time that the CocoaPods do install by these green lines.
[09:36] Our app launches, and we see right away this beautiful Filestack file picker appear, offering a wide array of cloud services to upload files into your app from, including even a simple web search, in addition to, for instance, just grabbing a file from Dropbox.