From d666f30665e4cd336e1a1017954447f486a3e8ce Mon Sep 17 00:00:00 2001 From: Raul Gomez Acuna Date: Thu, 29 Jun 2017 01:08:47 -0700 Subject: [PATCH] react-native link support for native Android modules developed in Kotlin 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 https://github.com/facebook/react-native/pull/14660 Differential Revision: D5316981 Pulled By: shergin fbshipit-source-id: 98354ba1e1ce1080a9a4b9958ef39893472038a1 --- local-cli/core/__fixtures__/android.js | 28 +++++++++++-------- .../core/__fixtures__/files/ReactPackage.java | 2 +- .../core/__fixtures__/files/ReactPackage.kt | 19 +++++++++++++ .../android/findPackageClassName.spec.js | 15 ++++++++-- .../core/android/findPackageClassName.js | 8 +++--- 5 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 local-cli/core/__fixtures__/files/ReactPackage.kt diff --git a/local-cli/core/__fixtures__/android.js b/local-cli/core/__fixtures__/android.js index d77797098..2a94869e2 100644 --- a/local-cli/core/__fixtures__/android.js +++ b/local-cli/core/__fixtures__/android.js @@ -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: { diff --git a/local-cli/core/__fixtures__/files/ReactPackage.java b/local-cli/core/__fixtures__/files/ReactPackage.java index a884062d8..1f65e4f5f 100644 --- a/local-cli/core/__fixtures__/files/ReactPackage.java +++ b/local-cli/core/__fixtures__/files/ReactPackage.java @@ -10,7 +10,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; -public class SomeExamplePackage implements ReactPackage { +public class SomeExampleJavaPackage implements ReactPackage { @Override public List createNativeModules( diff --git a/local-cli/core/__fixtures__/files/ReactPackage.kt b/local-cli/core/__fixtures__/files/ReactPackage.kt new file mode 100644 index 000000000..f17b5b760 --- /dev/null +++ b/local-cli/core/__fixtures__/files/ReactPackage.kt @@ -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 + = mutableListOf(MaterialPaletteModule(reactContext)) + + override fun createViewManagers(reactContext: ReactApplicationContext?): + MutableList> = Collections.emptyList() + +} diff --git a/local-cli/core/__tests__/android/findPackageClassName.spec.js b/local-cli/core/__tests__/android/findPackageClassName.spec.js index 5c5189184..a1cb71481 100644 --- a/local-cli/core/__tests__/android/findPackageClassName.spec.js +++ b/local-cli/core/__tests__/android/findPackageClassName.spec.js @@ -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', () => { diff --git a/local-cli/core/android/findPackageClassName.js b/local-cli/core/android/findPackageClassName.js index 3552e1c44..8d59aba26 100644 --- a/local-cli/core/android/findPackageClassName.js +++ b/local-cli/core/android/findPackageClassName.js @@ -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;