Skip to content

Commit

Permalink
react-native link support for native Android modules developed in Kotlin
Browse files Browse the repository at this point in the history
Summary:
Currently React Native cli does not support linking native Android modules written in Kotlin. This PR aims to add support to it and closes #14561

- New unit tests added to verify the added functionality, they can be found inside:
`local-cli/core/__tests__/android/findPackageClassName.spec.js`

- Existing unit tests passed.
Closes #14660

Differential Revision: D5316981

Pulled By: shergin

fbshipit-source-id: 98354ba1e1ce1080a9a4b9958ef39893472038a1
  • Loading branch information
rgommezz authored and facebook-github-bot committed Jun 29, 2017
1 parent 0797dae commit d666f30
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 18 deletions.
28 changes: 17 additions & 11 deletions local-cli/core/__fixtures__/android.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,27 @@ const path = require('path');
const manifest = fs.readFileSync(path.join(__dirname, './files/AndroidManifest.xml'));
const mainJavaClass = fs.readFileSync(path.join(__dirname, './files/Main.java'));

exports.valid = {
src: {
'AndroidManifest.xml': manifest,
main: {
com: {
some: {
example: {
'Main.java': mainJavaClass,
'ReactPackage.java': fs.readFileSync(path.join(__dirname, './files/ReactPackage.java')),
function generateValidFileStructure(classFileName) {
return {
src: {
'AndroidManifest.xml': manifest,
main: {
com: {
some: {
example: {
'Main.java': mainJavaClass,
[classFileName]: fs.readFileSync(path.join(__dirname, `./files/${classFileName}`)),
},
},
},
},
},
},
};
};
}

exports.valid = generateValidFileStructure('ReactPackage.java');

exports.validKotlin = generateValidFileStructure('ReactPackage.kt');

exports.userConfigManifest = {
src: {
Expand Down
2 changes: 1 addition & 1 deletion local-cli/core/__fixtures__/files/ReactPackage.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
import java.util.Collections;
import java.util.List;

public class SomeExamplePackage implements ReactPackage {
public class SomeExampleJavaPackage implements ReactPackage {

@Override
public List<NativeModule> createNativeModules(
Expand Down
19 changes: 19 additions & 0 deletions local-cli/core/__fixtures__/files/ReactPackage.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
package com.some.example;

import android.view.View
import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ReactShadowNode
import com.facebook.react.uimanager.ViewManager
import java.util.*

class SomeExampleKotlinPackage : ReactPackage {

override fun createNativeModules(reactContext: ReactApplicationContext): MutableList<NativeModule>
= mutableListOf(MaterialPaletteModule(reactContext))

override fun createViewManagers(reactContext: ReactApplicationContext?):
MutableList<ViewManager<View, ReactShadowNode>> = Collections.emptyList()

}
15 changes: 13 additions & 2 deletions local-cli/core/__tests__/android/findPackageClassName.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,25 @@ describe('android::findPackageClassName', () => {
beforeAll(() => {
mockFS({
empty: {},
flat: {
flatJava: {
android: mocks.valid,
},
flatKotlin: {
android: mocks.validKotlin,
},
});
});

it('returns manifest content if file exists in the folder', () => {
expect(typeof findPackageClassName('flat')).toBe('string');
expect(typeof findPackageClassName('flatJava')).toBe('string');
});

it('returns the name of the java class implementing ReactPackage', () => {
expect(findPackageClassName('flatJava')).toBe('SomeExampleJavaPackage');
});

it('returns the name of the kotlin class implementing ReactPackage', () => {
expect(findPackageClassName('flatKotlin')).toBe('SomeExampleKotlinPackage');
});

it('returns `null` if there are no matches', () => {
Expand Down
8 changes: 4 additions & 4 deletions local-cli/core/android/findPackageClassName.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,16 @@ const path = require('path');

/**
* Gets package's class name (class that implements ReactPackage)
* by searching for its declaration in all Java files present in the folder
* by searching for its declaration in all Java/Kotlin files present in the folder
*
* @param {String} folder Folder to find java files
* @param {String} folder Folder to find java/kt files
*/
module.exports = function getPackageClassName(folder) {
const files = glob.sync('**/*.java', { cwd: folder });
const files = glob.sync('**/+(*.java|*.kt)', { cwd: folder });

const packages = files
.map(filePath => fs.readFileSync(path.join(folder, filePath), 'utf8'))
.map(file => file.match(/class (.*) implements ReactPackage/))
.map(file => file.match(/class (.*) +(implements|:) ReactPackage/))
.filter(match => match);

return packages.length ? packages[0][1] : null;
Expand Down

0 comments on commit d666f30

Please sign in to comment.