Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 58 additions & 9 deletions src/create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,41 @@ import pack from '../package.json';
const BINARIES = /(gradlew|\.(jar|keystore|png|jpg|gif))$/;

const COMMON_FILES = path.resolve(__dirname, '../templates/common');
const NATIVE_FILES = path.resolve(__dirname, '../templates/native-library');
const JS_FILES = path.resolve(__dirname, '../templates/js-library');
const EXPO_FILES = path.resolve(__dirname, '../templates/expo-library');
const CPP_FILES = path.resolve(__dirname, '../templates/cpp-library');
const OBJC_FILES = path.resolve(__dirname, '../templates/objc-library');
const SWIFT_FILES = path.resolve(__dirname, '../templates/swift-library');
const EXAMPLE_FILES = path.resolve(__dirname, '../templates/example');

// Android
const NATIVE_FILES = (moduleType: ModuleType) => {
switch (moduleType) {
case 'module':
return path.resolve(__dirname, '../templates/native-library');
case 'view':
return path.resolve(__dirname, '../templates/native-view-library');
}
};

// Objc
const OBJC_FILES = (moduleType: ModuleType) => {
switch (moduleType) {
case 'module':
return path.resolve(__dirname, '../templates/objc-library');
case 'view':
return path.resolve(__dirname, '../templates/objc-view-library');
}
};

// Swift
const SWIFT_FILES = (moduleType: ModuleType) => {
switch (moduleType) {
case 'module':
return path.resolve(__dirname, '../templates/swift-library');
case 'view':
return path.resolve(__dirname, '../templates/swift-view-library');
}
};

type ArgName =
| 'slug'
| 'description'
Expand All @@ -30,14 +57,25 @@ type ArgName =
| 'repo-url'
| 'type';

type ModuleType = 'module' | 'view';

type LibraryType =
| 'native-view'
| 'native-view-swift'
| 'native'
| 'native-swift'
| 'js'
| 'cpp'
| 'expo';

type Answers = {
slug: string;
description: string;
authorName: string;
authorEmail: string;
authorUrl: string;
repoUrl: string;
type: 'native' | 'native-swift' | 'js' | 'cpp' | 'expo';
type: LibraryType;
};

export const args: Record<ArgName, yargs.Options> = {
Expand Down Expand Up @@ -168,6 +206,8 @@ export default async function create(argv: yargs.Arguments<any>) {
message: 'What type of package do you want to develop?',
// @ts-ignore - seems types are wrong for inquirer
choices: [
{ name: 'Native view in Kotlin and Objective-C', value: 'native-view' },
{ name: 'Native view in Kotlin and Swift', value: 'native-view-swift' },
{ name: 'Native module in Kotlin and Objective-C', value: 'native' },
{ name: 'Native module in Kotlin and Swift', value: 'native-swift' },
{ name: 'Native module with C++ code', value: 'cpp' },
Expand Down Expand Up @@ -211,6 +251,8 @@ export default async function create(argv: yargs.Arguments<any>) {
} as Answers;

const project = slug.replace(/^(react-native-|@[^/]+\/)/, '');
const moduleType: ModuleType =
type === 'native-view' || type === 'native-view-swift' ? 'view' : 'module';

const options = {
bob: {
Expand All @@ -226,10 +268,16 @@ export default async function create(argv: yargs.Arguments<any>) {
.slice(1)}`,
package: slug.replace(/[^a-z0-9]/g, '').toLowerCase(),
podspec: slug.replace(/[^a-z0-9]+/g, '-').replace(/^-/, ''),
native: type === 'native' || type === 'cpp' || 'native-swift',
native:
type === 'native' ||
type === 'cpp' ||
'native-swift' ||
'native-view' ||
'native-view-swift',
cpp: type === 'cpp',
swift: type === 'native-swift',
swift: type === 'native-swift' || 'native-view-swift',
module: type !== 'js',
moduleType,
},
author: {
name: authorName,
Expand Down Expand Up @@ -284,14 +332,15 @@ export default async function create(argv: yargs.Arguments<any>) {
path.join(EXAMPLE_FILES, 'example'),
path.join(folder, 'example')
);
await copyDir(NATIVE_FILES, folder);

await copyDir(NATIVE_FILES(moduleType), folder);

if (type === 'cpp') {
await copyDir(CPP_FILES, folder);
} else if (type === 'native-swift') {
await copyDir(SWIFT_FILES, folder);
await copyDir(SWIFT_FILES(moduleType), folder);
} else {
await copyDir(OBJC_FILES, folder);
await copyDir(OBJC_FILES(moduleType), folder);
}
}

Expand Down
22 changes: 18 additions & 4 deletions templates/common/example/src/App.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,21 @@
import * as React from 'react';
<% if (project.moduleType === "view") { %>
import { StyleSheet, View } from 'react-native';
import <%= project.name %>ViewManager from '<%= project.slug %>';
<% } else {%>
import { StyleSheet, View, Text } from 'react-native';
import <%= project.name %>, { <%= project.name %>ViewManager } from '<%= project.slug %>';
import <%= project.name %> from '<%= project.slug %>';
<% }%>

<% if (project.moduleType === "view") { %>
export default function App() {
return (
<View style={styles.container}>
<<%= project.name %>ViewManager color="#32a852" style={styles.box} />
</View>
);
}
<% } else {%>
export default function App() {
const [result, setResult] = React.useState<number | undefined>();

Expand All @@ -12,10 +26,10 @@ export default function App() {
return (
<View style={styles.container}>
<Text>Result: {result}</Text>
<<%= project.name %>ViewManager color="#32a852" style={styles.box} />
</View>
);
}
}
<% }%>

const styles = StyleSheet.create({
container: {
Expand All @@ -28,4 +42,4 @@ const styles = StyleSheet.create({
height: 60,
marginVertical: 20,
},
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ class <%= project.name %>Package : ReactPackage {
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return listOf(<%= project.name %>ViewManager())
return emptyList()
}
}
11 changes: 1 addition & 10 deletions templates/native-library/src/index.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import { NativeModules, requireNativeComponent, ViewStyle } from 'react-native';
import { NativeModules } from 'react-native';

type <%= project.name %>Type = {
multiply(a: number, b: number): Promise<number>;
};

type <%= project.name %>Props = {
color: string;
style: ViewStyle;
};

const { <%= project.name %> } = NativeModules;

export const <%= project.name %>ViewManager = requireNativeComponent<<%= project.name %>Props>(
'<%= project.name %>View'
);

export default <%= project.name %> as <%= project.name %>Type;
143 changes: 143 additions & 0 deletions templates/native-view-library/android/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
buildscript {
// Buildscript is evaluated before everything else so we can't use getExtOrDefault
def kotlin_version = rootProject.ext.has('kotlinVersion') ? rootProject.ext.get('kotlinVersion') : project.properties['<%= project.name %>_kotlinVersion']

repositories {
google()
jcenter()
}

dependencies {
classpath 'com.android.tools.build:gradle:3.2.1'
// noinspection DifferentKotlinGradleVersion
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}

apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'

def getExtOrDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['<%= project.name %>_' + name]
}

def getExtOrIntegerDefault(name) {
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['<%= project.name %>_' + name]).toInteger()
}

android {
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
buildToolsVersion getExtOrDefault('buildToolsVersion')
defaultConfig {
minSdkVersion 16
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
versionCode 1
versionName "1.0"
<% if (project.cpp) {%>
externalNativeBuild {
cmake {
cppFlags "-O2 -frtti -fexceptions -Wall -fstack-protector-all"
abiFilters 'x86', 'x86_64', 'armeabi-v7a', 'arm64-v8a'
}
}
<% } %>
}
<% if (project.cpp) {%>
externalNativeBuild {
cmake {
path "CMakeLists.txt"
}
}
<% } %>
buildTypes {
release {
minifyEnabled false
}
}
lintOptions {
disable 'GradleCompatible'
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}

repositories {
mavenCentral()
jcenter()
google()

def found = false
def defaultDir = null
def androidSourcesName = 'React Native sources'

if (rootProject.ext.has('reactNativeAndroidRoot')) {
defaultDir = rootProject.ext.get('reactNativeAndroidRoot')
} else {
defaultDir = new File(
projectDir,
'/../../../node_modules/react-native/android'
)
}

if (defaultDir.exists()) {
maven {
url defaultDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${defaultDir.canonicalPath}")
found = true
} else {
def parentDir = rootProject.projectDir

1.upto(5, {
if (found) return true
parentDir = parentDir.parentFile

def androidSourcesDir = new File(
parentDir,
'node_modules/react-native'
)

def androidPrebuiltBinaryDir = new File(
parentDir,
'node_modules/react-native/android'
)

if (androidPrebuiltBinaryDir.exists()) {
maven {
url androidPrebuiltBinaryDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${androidPrebuiltBinaryDir.canonicalPath}")
found = true
} else if (androidSourcesDir.exists()) {
maven {
url androidSourcesDir.toString()
name androidSourcesName
}

logger.info(":${project.name}:reactNativeAndroidRoot ${androidSourcesDir.canonicalPath}")
found = true
}
})
}

if (!found) {
throw new GradleException(
"${project.name}: unable to locate React Native android sources. " +
"Ensure you have you installed React Native as a dependency in your project and try again."
)
}
}

def kotlin_version = getExtOrDefault('kotlinVersion')

dependencies {
// noinspection GradleDynamicVersion
api 'com.facebook.react:react-native:+'
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
}
4 changes: 4 additions & 0 deletions templates/native-view-library/android/gradle.properties
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<%= project.name %>_kotlinVersion=1.3.50
<%= project.name %>_compileSdkVersion=28
<%= project.name %>_buildToolsVersion=28.0.3
<%= project.name %>_targetSdkVersion=28
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.<%= project.package %>">

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package com.<%= project.package %>

import com.facebook.react.ReactPackage
import com.facebook.react.bridge.NativeModule
import com.facebook.react.bridge.ReactApplicationContext
import com.facebook.react.uimanager.ViewManager


class <%= project.name %>Package : ReactPackage {
override fun createNativeModules(reactContext: ReactApplicationContext): List<NativeModule> {
return emptyList()
}

override fun createViewManagers(reactContext: ReactApplicationContext): List<ViewManager<*, *>> {
return listOf(<%= project.name %>ViewManager())
}
}
Loading