xref: /expo/packages/@unimodules/core/README.md (revision 8f4be4e2)
1# @unimodules/core
2
3## JavaScript installation
4
5```sh
6$ yarn add @unimodules/core
7
8# or
9
10$ npm install @unimodules/core --save
11```
12
13## Installation
14
15If you are using `react-native-unimodules`, this package will already be installed and configured!
16
17### iOS (Cocoapods)
18
19If you're using Cocoapods, add the following dependency to your `Podfile`:
20
21`pod 'UMCore', path: '../node_modules/@unimodules/core/ios'`
22
23and run `pod install`.
24
25### Android
26
271.  Append the following lines to `android/settings.gradle`:
28    ```gradle
29    include ':unimodules-core'
30    project(':unimodules-core').projectDir = new File(rootProject.projectDir, '../node_modules/@unimodules/core/android')
31    ```
322.  Insert the following lines inside the dependencies block in `android/app/build.gradle`:
33    ```gradle
34    compile project(':unimodules-core')
35    ```
363.  If you're using ProGuard, you'll need to append these lines to your ProGuard rules file for it not to strip out methods required for Expo modules to work.
37    ```pro
38    -keepclassmembers class * {
39      @org.unimodules.interfaces.ExpoProp *;
40    }
41    -keepclassmembers class * {
42      @org.unimodules.interfaces.ExpoMethod *;
43    }
44    ```
45
46## Usage
47
48### Glossary
49
50- **Native code** — iOS/Android native code.
51- **Client code** — code _over the bridge_, for React Native it would be the JavaScript app, for Flutter it would be Flutter code.
52- **Internal module** — a class implementing `UMInternalModule`/`org.unimodules.interfaces.InternalModule` interface. Its instance can be exposed internally to other modules via *Module Registry* (how dependants reference modules differs between platforms).
53- **Module interface** — an interface that should be implemented by the dependency so it can act as an implementation of it.
54
55    On Android modules implement an external interface (`expo-file-system` package implements interface provided by `expo-file-system-interface`). Dependants may access the implementations by calling
56    ```java
57    public <T> T getModule(Class<T> interfaceClass);
58    ```
59    method on the module registry.
60
61    On iOS its the consumer who defines required protocol. Implementations are identified by a protocol. Dependants access the implementation by calling
62    ```objc
63    - (id)getModuleImplementingProtocol:(Protocol *)protocol;
64    ```
65    method on the module registry.
66- **Module Registry** — well, a registry of modules. Instance of this class is used to fetch another internal or exported module.
67- **Exported methods** — a subset of instance methods of a given module that should get exposed to client code by specific platform adapter.
68- **Exported module** — a subclass of `{UM,org.unimodules.}ExportedModule`. Its methods annotated with `org.unimodules.ExpoMethod`/`UM_EXPORT_METHOD_AS` are exported to client code.
69- **View manager** — a class capable of providing platform adapter with custom views.
70
71### Registering modules in the registry
72
73#### iOS
74
751. Open the header file for your module.
762. Import `<UMCore/UMInternalModule.h>`.
773. Add `UMModule` to a list of implemented interfaces by the module instances (eg. `NSObject <UMInternalModule>`).
784. Open the implementation file for your module and implement methods required by the protocol.
795. Use `UM_REGISTER_MODULE();` macro to register the module.
806. That's it!
81
82#### Android
83
841. Add `org.unimodules.interfaces.InternalModule` to your class's imports.
852. Make your module class implement `InternalModule` interface.
86    1. Implement `public List<Class> getExportedInterfaces();`. Return a list of module interfaces implemented by the class, for example:
87        ```java
88        return Collections.singletonList((Class) org.unimodules.interfaces.filesystem.FileSystem.class);
89        ```
903. Create a `Package` class for your module, unless you already have one.
91    1. A `Package` class should implement `org.unimodules.Package` interface (a `BasePackage` class is provided for you not to have to implement all the initialization flavors at once).
92    2. Add the `Package` to a `List` provided to `ModuleRegistryBuilder`.
93        ```java
94        new ModuleRegistryBuilder(
95          Arrays.<Package>asList(
96            new FileSystemPackage()
97          )
98        )
99        ```
1004. Add your module to be returned by `List<InternalModule> createInternalModules(Context context);`.
1015. You're good to go!
102
103### Exporting module to client code
104
105#### iOS
106
107When registering your module for export to client code, you must first decide whether the class will only be exported to client code or will it be both internal and exported module. If the former is applicable, you easily just subclass `UMExportedModule` and use macro `UM_EXPORT_MODULE(clientCodeName)` to provide a name under which it should be exported. If your module should be both internal and exported module, you also have to subclass `UMExportedModule`, but this time use `UM_REGISTER_MODULE()` in the implementation and then manually override methods `exportedInterfaces` and `exportedModuleName`.
108
109#### Android
110
111Subclass `org.unimodules.ExportedModule` and add your module to a list returned by `Package` in `createExportedModules()`.
112
113### Exporting methods and calling exported methods
114
115#### iOS
116
117Use `UM_EXPORT_METHOD_AS(exportedName, definition)` macro to export given method to client code. Note that for the module to be available in the client code you have to provide a non-empty client code name in `UM_EXPORT_MODULE(clientCodeName)` or `- (const NSString *)exportedModuleName`. For now, arguments have to use basic, object types, like `NSString *`, `NSDictionary *`, `NSNumber *`. Methods are required to receive `UMPromiseResolveBlock` and `UMPromiseRejectBlock` as two last arguments.
118
119#### Android
120
121Given that your module subclasses `org.unimodules.ExportedModule` and it is returned by the respective `Package`, you just have to annotate the given method with `@ExpoMethod` annotation. Methods are required to receive `org.unimodules.Promise` as the last argument.
122
123### Exporting constants to client code
124
125#### iOS
126
127Implement `- (NSDictionary *)constantsToExport` method to export constants to client code.
128
129#### Android
130
131Override `public Map<String, Object> getConstants();` method to export constants to client code.
132
133### Creating a custom view manager
134
135#### iOS
136
137Subclass `UMViewManager` and override at least `- (UIView *)view` and `- (NSString *)viewName`. Register it with `UM_REGISTER_MODULE()`.
138
139Use `UM_VIEW_PROPERTY(propName, propClass, viewClass)` to define custom view properties.
140
141#### Android
142
143TODO: ViewManager from interface to a class
144
145Implement `org.unimodules.interfaces.ViewManager` in your class and respond with its instance in `List<ViewManager> createViewManagers(Context context);` in corresponding `Package`.
146
147Annotate prop setter methods with `@ExpoProp(name = <name>)` to define custom view properties.
148