Skip to content

Commit 17c28e7

Browse files
vonovakWoLewicki
andauthored
feat(android)!: new arch support (#730)
* wip * finished * works on both platforms * rnta update * finish? * run android CI * minor fixes * try android build * try android build * fix path? * update lockfile * fix ci pod install * do not build ios w/ new arch * update deps * do not uselessly export type * do not codegen android component * undo changes which weren't needed for successful build on old arch * various refactors * finalizing refactors * simplify getReactModuleInfoProvider * remove comments * readme updated * deps update --------- Co-authored-by: Wojciech Lewicki <[email protected]>
1 parent e81826b commit 17c28e7

29 files changed

+3891
-2493
lines changed

.circleci/config.yml

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,26 @@ jobs:
3030
command: yarn test
3131
name: Jest
3232

33+
# new_arch_ios_build:
34+
# executor:
35+
# name: rn/macos
36+
# xcode_version: '14.0.0'
37+
# steps:
38+
# - checkout
39+
# - run:
40+
# command: yarn install --frozen-lockfile
41+
# name: yarn install
42+
# - run:
43+
# command: cd example && yarn install --frozen-lockfile && cd -
44+
# name: yarn install example
45+
# - run:
46+
# command: (cd example && RCT_NEW_ARCH_ENABLED=1 npx pod-install)
47+
# name: pod install
48+
# - run:
49+
# command: yarn detox:ios:build:release
50+
# name: build app with new arch
51+
52+
3353
e2e_release_ios:
3454
executor:
3555
name: rn/macos
@@ -100,6 +120,46 @@ jobs:
100120
- store_artifacts:
101121
path: ./artifacts
102122

123+
124+
e2e_release_android_new_arch:
125+
executor:
126+
name: android/android-machine
127+
resource-class: large
128+
tag: '2022.01.1'
129+
steps:
130+
- checkout
131+
- run:
132+
command: avdmanager list
133+
name: list avds
134+
- android/create-avd:
135+
avd-name: TestingAVD
136+
system-image: system-images;android-29;default;x86
137+
additional-args: --device pixel_4_xl
138+
install: true
139+
- android/start-emulator:
140+
avd-name: TestingAVD
141+
no-window: true
142+
restore-gradle-cache-prefix: v1a
143+
post-emulator-launch-assemble-command: "pwd"
144+
- android/disable-animations
145+
- run:
146+
command: npm install --global yarn
147+
name: install yarn
148+
- run:
149+
command: yarn install --frozen-lockfile
150+
name: yarn install
151+
- run:
152+
command: yarn bundle:android
153+
name: bundle js
154+
- run:
155+
command: ORG_GRADLE_PROJECT_newArchEnabled=true yarn detox:android:build:release
156+
name: build app for e2e tests
157+
- run:
158+
command: yarn detox:android:test:release
159+
name: run e2e tests
160+
- store_artifacts:
161+
path: ./artifacts
162+
103163
publish:
104164
executor:
105165
name: rn/linux_js
@@ -121,9 +181,11 @@ workflows:
121181
- analyse_js
122182
- e2e_release_ios
123183
- e2e_release_android
184+
- e2e_release_android_new_arch
124185
- publish:
125186
requires:
126187
- e2e_release_android
188+
- e2e_release_android_new_arch
127189
- e2e_release_ios
128190
filters:
129191
branches:

.flowconfig

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77

88
; Ignore polyfills
99
node_modules/react-native/Libraries/polyfills/.*
10+
.*/**/malformed_package_json/package.json
11+
1012

1113
; Flow doesn't support platforms
1214
.*/Libraries/Utilities/LoadingView.js

README.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
### 🚧🚧 Looking for collaborators and backers 🚧🚧
1+
### 🚧🚧 Looking for collaborators and financial backers 🚧🚧
22

33
See this [issue](https://github.com/react-native-datetimepicker/datetimepicker/issues/313).
44

@@ -93,7 +93,9 @@ React Native date & time picker component for iOS, Android and Windows.
9393
## Requirements
9494

9595
- Only Android API level >=21 (Android 5), iOS >= 11 are supported.
96-
- Tested with Xcode 14.0 and RN 0.70. Other configurations are very likely to work as well but have not been tested.
96+
- Tested with Xcode 14.0 and RN 0.71.4. Other configurations are very likely to work as well but have not been tested.
97+
98+
The module supports the [new React Native architecture](https://reactnative.dev/docs/next/the-new-architecture/why) (Fabric rendering of iOS components, and turbomodules on Android). If you are using the new architecture, you will need to use React Native 0.71.4 or higher.
9799

98100
## Expo users notice
99101

android/build.gradle

Lines changed: 47 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,34 +1,62 @@
1-
apply plugin: 'com.android.library'
1+
buildscript {
2+
repositories {
3+
google()
4+
mavenCentral()
5+
}
6+
}
27

3-
def safeExtGet(prop, fallback) {
4-
def retValue = rootProject.ext.has(prop) ? rootProject.ext.get(prop) : fallback
5-
return retValue
8+
def getExtOrIntegerDefault(name) {
9+
return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['ReactNativeDateTimePicker_' + name]).toInteger()
610
}
711

12+
def isNewArchitectureEnabled() {
13+
// To opt-in for the New Architecture, you can either:
14+
// - Set `newArchEnabled` to true inside the `gradle.properties` file
15+
// - Invoke gradle with `-newArchEnabled=true`
16+
// - Set an environment variable `ORG_GRADLE_PROJECT_newArchEnabled=true`
17+
return project.hasProperty("newArchEnabled") && project.newArchEnabled == "true"
18+
}
19+
20+
apply plugin: 'com.android.library'
21+
if (isNewArchitectureEnabled()) {
22+
apply plugin: "com.facebook.react"
23+
}
24+
25+
826
android {
9-
compileSdkVersion safeExtGet('compileSdkVersion', 28)
10-
buildToolsVersion safeExtGet('buildToolsVersion', '28.0.3')
27+
compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
28+
29+
// Used to override the NDK path/version on internal CI or by allowing
30+
// users to customize the NDK path/version from their root project (e.g. for M1 support)
31+
if (rootProject.hasProperty("ndkPath")) {
32+
ndkPath rootProject.ext.ndkPath
33+
}
34+
if (rootProject.hasProperty("ndkVersion")) {
35+
ndkVersion rootProject.ext.ndkVersion
36+
}
1137

1238
defaultConfig {
13-
minSdkVersion safeExtGet('minSdkVersion', 21)
14-
targetSdkVersion safeExtGet('targetSdkVersion', 28)
15-
versionCode 1
16-
versionName "1.0"
39+
minSdkVersion getExtOrIntegerDefault('minSdkVersion')
40+
targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
41+
buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
1742
}
18-
lintOptions {
19-
abortOnError false
43+
44+
sourceSets.main {
45+
java {
46+
if (!isNewArchitectureEnabled()) {
47+
srcDirs += 'src/paper/java'
48+
}
49+
}
2050
}
2151
}
2252

2353
repositories {
24-
mavenLocal()
25-
maven {
26-
// All of React Native (JS, Obj-C sources, Android binaries) is installed from npm
27-
url("$rootDir/../node_modules/react-native/android")
28-
}
29-
google()
54+
google()
55+
mavenLocal()
56+
mavenCentral()
3057
}
3158

3259
dependencies {
33-
implementation "com.facebook.react:react-native:+" // From node_modules
60+
//noinspection GradleDynamicVersion
61+
implementation 'com.facebook.react:react-native:+'
3462
}
Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,19 +31,19 @@
3131
* {@link NativeModule} that allows JS to show a native date picker dialog and get called back when
3232
* the user selects a date.
3333
*/
34-
@ReactModule(name = RNDatePickerDialogModule.FRAGMENT_TAG)
35-
public class RNDatePickerDialogModule extends ReactContextBaseJavaModule {
34+
@ReactModule(name = DatePickerModule.NAME)
35+
public class DatePickerModule extends NativeModuleDatePickerSpec {
3636

3737
@VisibleForTesting
38-
public static final String FRAGMENT_TAG = "RNDatePickerAndroid";
38+
public static final String NAME = "RNDatePicker";
3939

40-
public RNDatePickerDialogModule(ReactApplicationContext reactContext) {
40+
public DatePickerModule(ReactApplicationContext reactContext) {
4141
super(reactContext);
4242
}
4343

4444
@Override
4545
public @NonNull String getName() {
46-
return RNDatePickerDialogModule.FRAGMENT_TAG;
46+
return NAME;
4747
}
4848

4949
private class DatePickerDialogListener implements OnDateSetListener, OnDismissListener, OnClickListener {
@@ -115,7 +115,7 @@ public void onClick(DialogInterface dialog, int which) {
115115
@ReactMethod
116116
public void dismiss(Promise promise) {
117117
FragmentActivity activity = (FragmentActivity) getCurrentActivity();
118-
dismissDialog(activity, FRAGMENT_TAG, promise);
118+
dismissDialog(activity, NAME, promise);
119119
}
120120
/**
121121
* Show a date picker dialog.
@@ -147,8 +147,8 @@ public void open(final ReadableMap options, final Promise promise) {
147147
FragmentActivity activity = (FragmentActivity) getCurrentActivity();
148148
if (activity == null) {
149149
promise.reject(
150-
RNConstants.ERROR_NO_ACTIVITY,
151-
"Tried to open a DatePicker dialog while not attached to an Activity");
150+
RNConstants.ERROR_NO_ACTIVITY,
151+
"Tried to open a DatePicker dialog while not attached to an Activity");
152152
return;
153153
}
154154

@@ -158,7 +158,7 @@ public void open(final ReadableMap options, final Promise promise) {
158158
@Override
159159
public void run() {
160160
RNDatePickerDialogFragment oldFragment =
161-
(RNDatePickerDialogFragment) fragmentManager.findFragmentByTag(FRAGMENT_TAG);
161+
(RNDatePickerDialogFragment) fragmentManager.findFragmentByTag(NAME);
162162

163163
if (oldFragment != null) {
164164
oldFragment.update(createFragmentArguments(options));
@@ -173,7 +173,7 @@ public void run() {
173173
fragment.setOnDismissListener(listener);
174174
fragment.setOnDateSetListener(listener);
175175
fragment.setOnNeutralButtonActionListener(listener);
176-
fragment.show(fragmentManager, FRAGMENT_TAG);
176+
fragment.show(fragmentManager, NAME);
177177
}
178178
});
179179
}

android/src/main/java/com/reactcommunity/rndatetimepicker/RNDatePickerDialogFragment.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import androidx.annotation.NonNull;
2626
import androidx.annotation.Nullable;
2727
import androidx.fragment.app.DialogFragment;
28+
2829
import android.widget.DatePicker;
2930

3031
import java.util.Calendar;
Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,71 @@
11
package com.reactcommunity.rndatetimepicker;
22

3-
import java.util.Arrays;
4-
import java.util.Collections;
5-
import java.util.List;
63

7-
import com.facebook.react.ReactPackage;
4+
import androidx.annotation.NonNull;
5+
import androidx.annotation.Nullable;
6+
7+
import com.facebook.react.TurboReactPackage;
88
import com.facebook.react.bridge.NativeModule;
99
import com.facebook.react.bridge.ReactApplicationContext;
10-
import com.facebook.react.uimanager.ViewManager;
11-
12-
public class RNDateTimePickerPackage implements ReactPackage {
13-
@Override
14-
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
15-
return Arrays.<NativeModule>asList(
16-
new RNDatePickerDialogModule(reactContext),
17-
new RNTimePickerDialogModule(reactContext)
18-
);
19-
}
10+
import com.facebook.react.module.model.ReactModuleInfo;
11+
import com.facebook.react.module.model.ReactModuleInfoProvider;
12+
13+
import java.util.ArrayList;
14+
import java.util.HashMap;
15+
import java.util.List;
16+
import java.util.Map;
2017

21-
@Override
22-
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
23-
return Collections.emptyList();
18+
public class RNDateTimePickerPackage extends TurboReactPackage {
19+
@Nullable
20+
@Override
21+
public NativeModule getModule(String name, ReactApplicationContext reactContext) {
22+
if (name.equals(DatePickerModule.NAME)) {
23+
return new DatePickerModule(reactContext);
24+
} else if (name.equals(TimePickerModule.NAME)) {
25+
return new TimePickerModule(reactContext);
26+
} else {
27+
return null;
2428
}
29+
}
30+
31+
@Override
32+
public ReactModuleInfoProvider getReactModuleInfoProvider() {
33+
return () -> {
34+
boolean isTurboModule = BuildConfig.IS_NEW_ARCHITECTURE_ENABLED;
35+
final Map<String, ReactModuleInfo> moduleInfos = new HashMap<>();
36+
moduleInfos.put(
37+
DatePickerModule.NAME,
38+
new ReactModuleInfo(
39+
DatePickerModule.NAME,
40+
DatePickerModule.NAME,
41+
false, // canOverrideExistingModule
42+
false, // needsEagerInit
43+
false, // hasConstants
44+
false, // isCxxModule
45+
isTurboModule // isTurboModule
46+
));
47+
moduleInfos.put(
48+
TimePickerModule.NAME,
49+
new ReactModuleInfo(
50+
TimePickerModule.NAME,
51+
TimePickerModule.NAME,
52+
false, // canOverrideExistingModule
53+
false, // needsEagerInit
54+
false, // hasConstants
55+
false, // isCxxModule
56+
isTurboModule // isTurboModule
57+
));
58+
return moduleInfos;
59+
};
60+
}
61+
62+
@NonNull
63+
@Override
64+
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
65+
List<NativeModule> modules = new ArrayList<>();
66+
modules.add(new DatePickerModule(reactContext));
67+
modules.add(new TimePickerModule(reactContext));
68+
69+
return modules;
70+
}
2571
}

0 commit comments

Comments
 (0)