Skip to content

Commit bcf3fb6

Browse files
committed
Merge remote-tracking branch 'origin/capture-app-start-errors-v7' into antonis/capture-app-start-errors-v8
# Conflicts: # packages/core/RNSentry.podspec # packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryDependencyContainerTests.h # packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryFramesTrackerListenerTests.h # packages/core/RNSentryCocoaTester/RNSentryCocoaTesterTests/RNSentryTests.m
2 parents 243a75e + 67dec90 commit bcf3fb6

File tree

122 files changed

+5409
-1084
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

122 files changed

+5409
-1084
lines changed

.github/workflows/sample-application.yml

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ jobs:
8282
- uses: ruby/setup-ruby@v1
8383
if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }}
8484
with:
85-
working-directory: ${{ matrix.platform == 'ios' && env.REACT_NATIVE_SAMPLE_PATH || ' samples/react-native-macos' }}
85+
working-directory: ${{ matrix.platform == 'ios' && env.REACT_NATIVE_SAMPLE_PATH || 'samples/react-native-macos' }}
8686
ruby-version: '3.3.0' # based on what is used in the sample
8787
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
8888
cache-version: 1 # cache the installed gems
@@ -112,62 +112,39 @@ jobs:
112112
if: ${{ matrix.platform == 'ios' || matrix.platform == 'macos' }}
113113
working-directory: samples
114114
run: |
115-
[[ "${{ matrix.platform }}" == "ios" ]] && cd react-native/ios
116-
[[ "${{ matrix.platform }}" == "macos" ]] && cd react-native-macos/macos
115+
[[ "${{ matrix.platform }}" == "ios" ]] && cd react-native
116+
[[ "${{ matrix.platform }}" == "macos" ]] && cd react-native-macos
117117
118-
[[ "${{ matrix.build-type }}" == "production" ]] && ENABLE_PROD=1 || ENABLE_PROD=0
119-
[[ "${{ matrix.rn-architecture }}" == "new" ]] && ENABLE_NEW_ARCH=1 || ENABLE_NEW_ARCH=0
118+
[[ "${{ matrix.build-type }}" == "production" ]] && export ENABLE_PROD=1 || export ENABLE_PROD=0
119+
[[ "${{ matrix.rn-architecture }}" == "new" ]] && export ENABLE_NEW_ARCH=1 || export ENABLE_NEW_ARCH=0
120120
[[ "${{ matrix.ios-use-frameworks }}" == "dynamic-frameworks" ]] && export USE_FRAMEWORKS=dynamic
121-
echo "ENABLE_PROD=$ENABLE_PROD"
122-
echo "ENABLE_NEW_ARCH=$ENABLE_NEW_ARCH"
123-
PRODUCTION=$ENABLE_PROD RCT_NEW_ARCH_ENABLED=$ENABLE_NEW_ARCH bundle exec pod install
124-
cat Podfile.lock | grep $RN_SENTRY_POD_NAME
121+
122+
./scripts/pod-install.sh
125123
126124
- name: Build Android App
127125
if: ${{ matrix.platform == 'android' }}
128-
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/android
126+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
129127
run: |
130-
if [[ ${{ matrix.rn-architecture }} == 'new' ]]; then
131-
perl -i -pe's/newArchEnabled=false/newArchEnabled=true/g' gradle.properties
132-
echo 'New Architecture enabled'
133-
elif [[ ${{ matrix.rn-architecture }} == 'legacy' ]]; then
134-
perl -i -pe's/newArchEnabled=true/newArchEnabled=false/g' gradle.properties
135-
echo 'Legacy Architecture enabled'
136-
else
137-
echo 'No changes for architecture: ${{ matrix.rn-architecture }}'
138-
fi
139-
[[ "${{ matrix.build-type }}" == "production" ]] && CONFIG='Release' || CONFIG='Debug'
140-
echo "Building $CONFIG"
141-
[[ "${{ matrix.build-type }}" == "production" ]] && TEST_TYPE='release' || TEST_TYPE='debug'
142-
echo "Building $TEST_TYPE"
128+
export RN_ARCHITECTURE="${{ matrix.rn-architecture }}"
129+
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='release' || export CONFIG='debug'
143130
144-
./gradlew ":app:assemble$CONFIG" -PreactNativeArchitectures=x86
131+
./scripts/set-dsn-aos.mjs
132+
./scripts/build-android.sh -PreactNativeArchitectures=x86
145133
146134
- name: Build iOS App
147135
if: ${{ matrix.platform == 'ios' }}
148-
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}/ios
136+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
149137
run: |
150-
[[ "${{ matrix.build-type }}" == "production" ]] && CONFIG='Release' || CONFIG='Debug'
151-
echo "Building $CONFIG"
152-
mkdir -p "DerivedData"
153-
derivedData="$(cd "DerivedData" ; pwd -P)"
154-
set -o pipefail && xcodebuild \
155-
-workspace sentryreactnativesample.xcworkspace \
156-
-configuration "$CONFIG" \
157-
-scheme sentryreactnativesample \
158-
-sdk 'iphonesimulator' \
159-
-destination 'generic/platform=iOS Simulator' \
160-
ONLY_ACTIVE_ARCH=yes \
161-
-derivedDataPath "$derivedData" \
162-
build \
163-
| tee xcodebuild.log \
164-
| xcbeautify --quieter --is-ci --disable-colored-output
138+
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug'
139+
140+
./scripts/set-dsn-ios.mjs
141+
./scripts/build-ios.sh
165142
166143
- name: Build macOS App
167144
if: ${{ matrix.platform == 'macos' }}
168145
working-directory: samples/react-native-macos/macos
169146
run: |
170-
[[ "${{ matrix.build-type }}" == "production" ]] && CONFIG='Release' || CONFIG='Debug'
147+
[[ "${{ matrix.build-type }}" == "production" ]] && export CONFIG='Release' || export CONFIG='Debug'
171148
echo "Building $CONFIG"
172149
mkdir -p "DerivedData"
173150
derivedData="$(cd "DerivedData" ; pwd -P)"
@@ -184,19 +161,19 @@ jobs:
184161
185162
- name: Archive iOS App
186163
if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }}
164+
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
187165
run: |
188-
cd ${{ env.REACT_NATIVE_SAMPLE_PATH }}/ios/DerivedData/Build/Products/Release-iphonesimulator
189166
zip -r \
190167
${{ github.workspace }}/${{ env.IOS_APP_ARCHIVE_PATH }} \
191168
sentryreactnativesample.app
192169
193170
- name: Archive Android App
194171
if: ${{ matrix.platform == 'android' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' }}
195172
run: |
196-
mv ${{ env.REACT_NATIVE_SAMPLE_PATH }}/android/app/build/outputs/apk/release/app-release.apk app.apk
197173
zip -j \
198174
${{ env.ANDROID_APP_ARCHIVE_PATH }} \
199-
app.apk
175+
${{ env.REACT_NATIVE_SAMPLE_PATH }}/app.apk \
176+
${{ env.REACT_NATIVE_SAMPLE_PATH }}/app-androidTest.apk
200177
201178
- name: Upload iOS APP
202179
if: ${{ matrix.platform == 'ios' && matrix.rn-architecture == 'new' && matrix.build-type == 'production' && matrix.ios-use-frameworks == 'no-frameworks' }}
@@ -272,7 +249,9 @@ jobs:
272249
- name: Unzip Android APK
273250
if: ${{ matrix.platform == 'android' }}
274251
working-directory: ${{ env.REACT_NATIVE_SAMPLE_PATH }}
275-
run: unzip ${{ env.ANDROID_APP_ARCHIVE_PATH }}
252+
run: |
253+
unzip ${{ env.ANDROID_APP_ARCHIVE_PATH }}
254+
rm app-androidTest.apk
276255
277256
- name: Enable Corepack
278257
run: npm i -g corepack

CHANGELOG.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,75 @@
88
99
## Unreleased
1010

11+
### Features
12+
13+
- Capture App Start errors and crashes by initializing Sentry from `sentry.options.json` ([#4472](https://github.com/getsentry/sentry-react-native/pull/4472))
14+
15+
Create `sentry.options.json` in the React Native project root and set options the same as you currently have in `Sentry.init` in JS.
16+
17+
```json
18+
{
19+
"dsn": "https://key@example.io/value",
20+
}
21+
```
22+
23+
Initialize Sentry on the native layers by newly provided native methods.
24+
25+
```kotlin
26+
import io.sentry.react.RNSentrySDK
27+
28+
class MainApplication : Application(), ReactApplication {
29+
override fun onCreate() {
30+
super.onCreate()
31+
RNSentrySDK.init(this)
32+
}
33+
}
34+
```
35+
36+
```obj-c
37+
#import <RNSentry/RNSentry.h>
38+
39+
@implementation AppDelegate
40+
- (BOOL)application:(UIApplication *)application
41+
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
42+
{
43+
[RNSentrySDK start];
44+
return [super application:application didFinishLaunchingWithOptions:launchOptions];
45+
}
46+
@end
47+
```
48+
49+
- Add RNSentrySDK APIs support to @sentry/react-native/expo plugin ([#4633](https://github.com/getsentry/sentry-react-native/pull/4633))
50+
- Adds `useNativeInit` option to automatically initialize Sentry natively before JavaScript loads, enabling capture of app start errors
51+
```json
52+
{
53+
"expo": {
54+
"plugins": [
55+
[
56+
"@sentry/react-native/expo",
57+
{
58+
"useNativeInit": true
59+
}
60+
]
61+
]
62+
}
63+
}
64+
```
65+
66+
### Changes
67+
68+
- Load `optionsFile` into the JS bundle during Metro bundle process ([#4476](https://github.com/getsentry/sentry-react-native/pull/4476))
69+
- Add experimental version of `startWithConfigureOptions` for Apple platforms ([#4444](https://github.com/getsentry/sentry-react-native/pull/4444))
70+
- Add experimental version of `init` with optional `OptionsConfiguration<SentryAndroidOptions>` for Android ([#4451](https://github.com/getsentry/sentry-react-native/pull/4451))
71+
- Add initialization using `sentry.options.json` for Apple platforms ([#4447](https://github.com/getsentry/sentry-react-native/pull/4447))
72+
- Add initialization using `sentry.options.json` for Android ([#4451](https://github.com/getsentry/sentry-react-native/pull/4451))
73+
- Merge options from file with `Sentry.init` options in JS ([#4510](https://github.com/getsentry/sentry-react-native/pull/4510))
74+
75+
### Internal
76+
77+
- Extract iOS native initialization to standalone structures ([#4442](https://github.com/getsentry/sentry-react-native/pull/4442))
78+
- Extract Android native initialization to standalone structures ([#4445](https://github.com/getsentry/sentry-react-native/pull/4445))
79+
1180
### Dependencies
1281

1382
- Bump Cocoa SDK from v8.58.0 to v9.1.0 ([#5356](https://github.com/getsentry/sentry-react-native/pull/5356))

lerna.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@
88
"performance-tests/*"
99
],
1010
"npmClient": "yarn"
11-
}
11+
}

packages/core/RNSentry.podspec

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -42,10 +42,14 @@ Pod::Spec.new do |s|
4242
s.preserve_paths = '*.js'
4343

4444
s.source_files = 'ios/**/*.{h,m,mm}'
45-
s.public_header_files = 'ios/RNSentry.h'
45+
s.public_header_files = 'ios/RNSentry.h', 'ios/RNSentrySDK.h', 'ios/RNSentryStart.h', 'ios/RNSentryVersion.h', 'ios/RNSentryBreadcrumb.h', 'ios/RNSentryReplay.h', 'ios/RNSentryReplayBreadcrumbConverter.h', 'ios/Replay/RNSentryReplayMask.h', 'ios/Replay/RNSentryReplayUnmask.h', 'ios/RNSentryTimeToDisplay.h'
4646

4747
s.compiler_flags = other_cflags
4848

49+
s.pod_target_xcconfig = {
50+
'DEFINES_MODULE' => 'YES'
51+
}
52+
4953
s.dependency 'Sentry/HybridSDK', '9.1.0'
5054

5155
if defined? install_modules_dependencies
@@ -56,10 +60,10 @@ Pod::Spec.new do |s|
5660

5761
if is_new_arch_enabled then
5862
# New Architecture on React Native 0.70 and older
59-
s.pod_target_xcconfig = {
63+
s.pod_target_xcconfig.merge!({
6064
"HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
6165
"CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
62-
}
66+
})
6367

6468
s.dependency "React-RCTFabric" # Required for Fabric Components (like RCTViewComponentView)
6569
s.dependency "React-Codegen"
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
{
2+
"dsn": "invalid-dsn"
3+
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
invalid-options
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"dsn": "https://abcd@efgh.ingest.sentry.io/123456",
3+
"enableTracing": true,
4+
"tracesSampleRate": 1.0
5+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
package io.sentry.react
2+
3+
import androidx.test.ext.junit.runners.AndroidJUnit4
4+
import com.facebook.react.bridge.WritableArray
5+
import com.facebook.react.bridge.WritableMap
6+
import io.sentry.react.RNSentryJsonConverter.convertToWritable
7+
import org.json.JSONArray
8+
import org.json.JSONObject
9+
import org.junit.Assert.assertEquals
10+
import org.junit.Assert.assertNotNull
11+
import org.junit.Assert.assertNull
12+
import org.junit.Test
13+
import org.junit.runner.RunWith
14+
15+
@RunWith(AndroidJUnit4::class)
16+
class RNSentryJsonConverterTest {
17+
@Test
18+
fun testConvertToWritableWithSimpleJsonObject() {
19+
val jsonObject =
20+
JSONObject().apply {
21+
put("floatKey", 12.3f)
22+
put("doubleKey", 12.3)
23+
put("intKey", 123)
24+
put("stringKey", "test")
25+
put("nullKey", JSONObject.NULL)
26+
}
27+
28+
val result: WritableMap? = convertToWritable(jsonObject)
29+
30+
assertNotNull(result)
31+
assertEquals(12.3, result!!.getDouble("floatKey"), 0.0001)
32+
assertEquals(12.3, result.getDouble("doubleKey"), 0.0)
33+
assertEquals(123, result.getInt("intKey"))
34+
assertEquals("test", result.getString("stringKey"))
35+
assertNull(result.getString("nullKey"))
36+
}
37+
38+
@Test
39+
fun testConvertToWritableWithNestedJsonObject() {
40+
val jsonObject =
41+
JSONObject().apply {
42+
put(
43+
"nested",
44+
JSONObject().apply {
45+
put("key", "value")
46+
},
47+
)
48+
}
49+
50+
val result: WritableMap? = convertToWritable(jsonObject)
51+
52+
assertNotNull(result)
53+
val nestedMap = result!!.getMap("nested")
54+
assertNotNull(nestedMap)
55+
assertEquals("value", nestedMap!!.getString("key"))
56+
}
57+
58+
@Test
59+
fun testConvertToWritableWithJsonArray() {
60+
val jsonArray =
61+
JSONArray().apply {
62+
put(1)
63+
put(2.5)
64+
put("string")
65+
put(JSONObject.NULL)
66+
}
67+
68+
val result: WritableArray = convertToWritable(jsonArray)
69+
70+
assertEquals(1, result.getInt(0))
71+
assertEquals(2.5, result.getDouble(1), 0.0)
72+
assertEquals("string", result.getString(2))
73+
assertNull(result.getString(3))
74+
}
75+
76+
@Test
77+
fun testConvertToWritableWithNestedJsonArray() {
78+
val jsonObject =
79+
JSONObject().apply {
80+
put(
81+
"array",
82+
JSONArray().apply {
83+
put(
84+
JSONObject().apply {
85+
put("key1", "value1")
86+
},
87+
)
88+
put(
89+
JSONObject().apply {
90+
put("key2", "value2")
91+
},
92+
)
93+
},
94+
)
95+
}
96+
97+
val result: WritableMap? = convertToWritable(jsonObject)
98+
99+
val array = result?.getArray("array")
100+
assertEquals("value1", array?.getMap(0)?.getString("key1"))
101+
assertEquals("value2", array?.getMap(1)?.getString("key2"))
102+
}
103+
}

0 commit comments

Comments
 (0)