From 9a8703d9a07d0d0f52efbee8d4492e0293bad3b4 Mon Sep 17 00:00:00 2001 From: Abdelhamid Nasser <38096011+abdelhamid-f-nasser@users.noreply.github.com> Date: Mon, 29 Jan 2024 10:38:10 +0200 Subject: [PATCH 01/16] feat(example): add nested complex views (#1111) Jira ID: MOB-13737 --- .gitignore | 3 ++ .../default/src/components/InputField.tsx | 38 +++++++++++++++ .../default/src/components/NestedView.tsx | 31 ++++++++++++ examples/default/src/navigation/HomeStack.tsx | 7 +++ .../user-steps/BasicComponentsScreen.tsx | 4 +- .../screens/user-steps/ComplexViewsScreen.tsx | 47 +++++++++++++++++++ .../screens/user-steps/UserStepsScreen.tsx | 1 + 7 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 examples/default/src/components/InputField.tsx create mode 100644 examples/default/src/components/NestedView.tsx create mode 100644 examples/default/src/screens/user-steps/ComplexViewsScreen.tsx diff --git a/.gitignore b/.gitignore index f0e0669d2..50fb3439f 100644 --- a/.gitignore +++ b/.gitignore @@ -64,3 +64,6 @@ android/keystores/debug.keystore # Vscode local history .history/ + +# .idea run configurations +/.run/* diff --git a/examples/default/src/components/InputField.tsx b/examples/default/src/components/InputField.tsx new file mode 100644 index 000000000..91e789f80 --- /dev/null +++ b/examples/default/src/components/InputField.tsx @@ -0,0 +1,38 @@ +import React, { forwardRef } from 'react'; + +import { KeyboardTypeOptions, StyleSheet, TextInput } from 'react-native'; + +interface InputFieldProps { + placeholder?: string; + value?: string; + onChangeText?: (text: string) => void; + keyboardType?: KeyboardTypeOptions; +} + +export const InputField = forwardRef( + ({ placeholder, value, onChangeText, keyboardType, ...restProps }, ref) => { + return ( + + ); + }, +); + +const styles = StyleSheet.create({ + textInput: { + backgroundColor: 'white', + borderWidth: 1, + borderColor: '#ccc', + paddingVertical: 16, + paddingHorizontal: 24, + fontSize: 16, + borderRadius: 5, + }, +}); diff --git a/examples/default/src/components/NestedView.tsx b/examples/default/src/components/NestedView.tsx new file mode 100644 index 000000000..494fde9f2 --- /dev/null +++ b/examples/default/src/components/NestedView.tsx @@ -0,0 +1,31 @@ +import React from 'react'; + +import { Text } from 'native-base'; +import { StyleSheet, View } from 'react-native'; + +interface NestedViewProps { + children?: React.ReactNode; + depth: number; + breadth?: number; +} + +export const NestedView: React.FC = ({ depth, breadth = 1, children }) => { + if (!depth) { + return <>{children}; + } + return ( + + {depth} + {new Array(breadth).fill(null).map((_, index) => ( + + ))} + + ); +}; + +const styles = StyleSheet.create({ + container: { + borderWidth: 1, + padding: 1, + }, +}); diff --git a/examples/default/src/navigation/HomeStack.tsx b/examples/default/src/navigation/HomeStack.tsx index 360a27444..b3e1b76a4 100644 --- a/examples/default/src/navigation/HomeStack.tsx +++ b/examples/default/src/navigation/HomeStack.tsx @@ -12,6 +12,7 @@ import { UserStepsScreen } from '../screens/user-steps/UserStepsScreen'; import { BasicComponentsScreen } from '../screens/user-steps/BasicComponentsScreen'; import { ScrollViewScreen } from '../screens/user-steps/ScrollViewScreen'; import { FlatListScreen } from '../screens/user-steps/FlatListScreen'; +import { ComplexViewsScreen } from '../screens/user-steps/ComplexViewsScreen'; import { SectionListScreen } from '../screens/user-steps/SectionListScreen'; import { GesturesScreen } from '../screens/user-steps/GesturesScreen'; @@ -26,6 +27,7 @@ export type HomeStackParamList = { BasicComponents: undefined; ScrollView: undefined; FlatList: undefined; + ComplexViews: undefined; SectionList: undefined; Gestures: undefined; }; @@ -63,6 +65,11 @@ export const HomeStackNavigator: React.FC = () => { component={BasicComponentsScreen} options={{ title: 'Basic Components' }} /> + {
- +
diff --git a/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx b/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx new file mode 100644 index 000000000..0035d5775 --- /dev/null +++ b/examples/default/src/screens/user-steps/ComplexViewsScreen.tsx @@ -0,0 +1,47 @@ +import React, { useRef, useState } from 'react'; + +import { Screen } from '../../components/Screen'; +import { Section } from '../../components/Section'; +import { NestedView } from '../../components/NestedView'; +import { Button } from 'react-native'; +import { ScrollView, VStack } from 'native-base'; +import { InputField } from '../../components/InputField'; + +export const ComplexViewsScreen: React.FC = () => { + const initialDepth = 10; + const initialBreadth = 2; + + const depthRef = useRef(initialDepth); + const breadthRef = useRef(initialBreadth); + + const [depth, setDepth] = useState(initialDepth); + const [breadth, setBreadth] = useState(initialBreadth); + + function handleRender() { + setDepth(depthRef.current); + setBreadth(breadthRef.current); + } + + return ( + + +
+ + (depthRef.current = +text)} + /> + (breadthRef.current = +text)} + /> +
+
+
+ ); +}; diff --git a/examples/default/src/screens/user-steps/UserStepsScreen.tsx b/examples/default/src/screens/user-steps/UserStepsScreen.tsx index 219cd5bbd..dc0d26c10 100644 --- a/examples/default/src/screens/user-steps/UserStepsScreen.tsx +++ b/examples/default/src/screens/user-steps/UserStepsScreen.tsx @@ -14,6 +14,7 @@ export const UserStepsScreen: React.FC navigation.navigate('ScrollView')} /> navigation.navigate('FlatList')} /> navigation.navigate('SectionList')} /> + navigation.navigate('ComplexViews')} /> navigation.navigate('Gestures')} /> ); From e17074a515e6303c9f4ae30adb50bea4cfd48368 Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Tue, 30 Jan 2024 15:27:46 +0200 Subject: [PATCH 02/16] fix hybrid mode code push version init (#1108) --- .../instabug/reactlibrary/RNInstabugReactnativeModule.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index 6692a2597..bf568cbf8 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -144,7 +144,11 @@ public void run() { .setLogLevel(parsedLogLevel); if(codePushVersion != null) { - builder.setCodePushVersion(codePushVersion); + if(Instabug.isBuilt()) { + Instabug.setCodePushVersion(codePushVersion); + } else { + builder.setCodePushVersion(codePushVersion); + } } builder.build(); } From 4161fdb6d8a3c11b46c368d5835782950c4198c5 Mon Sep 17 00:00:00 2001 From: Abdelhamid Nasser <38096011+abdelhamid-f-nasser@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:31:50 +0200 Subject: [PATCH 03/16] chore(android): ignore jetbrains ide run configurations (#1110) Jira ID: MOB-13736 From 2ed0f24646f56aadd0272a4eaa83ff2733dcecd8 Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud <68241710+a7medev@users.noreply.github.com> Date: Wed, 31 Jan 2024 16:14:43 +0200 Subject: [PATCH 04/16] ci: migrate macos machines to m1 (#1114) --- .circleci/config.yml | 5 ++++- examples/default/ios/Podfile.lock | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f1df27eb1..f677b4bd7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -147,6 +147,7 @@ jobs: sync_generated_files: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 steps: - advanced-checkout/shallow-checkout - install_node_modules @@ -161,6 +162,7 @@ jobs: test_ios: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 working_directory: ~/project/examples/default environment: INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true @@ -192,7 +194,7 @@ jobs: e2e_ios: macos: xcode: 13.4.1 - resource_class: macos.x86.medium.gen2 + resource_class: macos.m1.medium.gen1 environment: INSTABUG_SOURCEMAPS_UPLOAD_DISABLE: true steps: @@ -321,6 +323,7 @@ jobs: publish: macos: xcode: 13.4.1 + resource_class: macos.m1.medium.gen1 working_directory: '~' steps: - advanced-checkout/shallow-checkout diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock index 45e5f48cf..5cd4fa4f0 100644 --- a/examples/default/ios/Podfile.lock +++ b/examples/default/ios/Podfile.lock @@ -795,4 +795,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d169b4508f413ff5d69cdf38428960e0828e6282 -COCOAPODS: 1.11.3 +COCOAPODS: 1.12.0 From 3123fe95fbbb4c9d9e2654e0d6ee0a99d106521f Mon Sep 17 00:00:00 2001 From: Abdelhamid Nasser <38096011+abdelhamid-f-nasser@users.noreply.github.com> Date: Mon, 5 Feb 2024 17:47:40 +0200 Subject: [PATCH 05/16] feat: support identify user by id (#1115) Jira ID: MOB-13746 --- CHANGELOG.md | 6 ++++++ .../RNInstabugReactnativeModule.java | 12 ++++++++--- .../RNInstabugReactnativeModuleTest.java | 21 +++++++++++++++---- .../ios/InstabugTests/InstabugSampleTests.m | 15 +++++++++++-- ios/RNInstabug/InstabugReactBridge.h | 2 +- ios/RNInstabug/InstabugReactBridge.m | 4 ++-- src/modules/Instabug.ts | 7 ++++--- src/native/NativeInstabug.ts | 2 +- test/modules/Instabug.spec.ts | 12 ++++++++++- 9 files changed, 64 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 361ce4d2e..d01016490 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # Changelog +## [Unreleased](https://github.com/Instabug/Instabug-React-Native/compare/v12.6.0...dev) + +### Added + +- Support user identification using ID ([#1115](https://github.com/Instabug/Instabug-React-Native/pull/1115)) + ## [12.6.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.5.0...v12.6.0) (January 14, 2024) ### Changed diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index bf568cbf8..57bcf1142 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -294,16 +294,22 @@ public void run() { * Set the user identity. * Instabug will pre-fill the user email in reports. * - * @param userName Username. * @param userEmail User's default email + * @param userName Username. + * @param userId User's ID */ @ReactMethod - public void identifyUser(final String userEmail, final String userName) { + public void identifyUser( + final String userEmail, + final String userName, + @Nullable final String userId + ) { MainThreadHandler.runOnMainThread(new Runnable() { @Override public void run() { try { - Instabug.identifyUser(userName, userEmail); + // The arguments get re-ordered here to match the API signature. + Instabug.identifyUser(userName, userEmail, userId); } catch (Exception e) { e.printStackTrace(); } diff --git a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java index 148d71d51..88174949a 100644 --- a/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java +++ b/android/src/test/java/com/instabug/reactlibrary/RNInstabugReactnativeModuleTest.java @@ -200,16 +200,29 @@ public void tearDown() { } @Test - public void givenArgs$identifyUser_whenQuery_thenShouldCallNativeApiWithArgs() { + public void testIdentifyUserWithNoId() { // given String email = "sali@instabug.com"; String userName = "salmaali"; + String id = null; // when - rnModule.identifyUser(email, userName); + rnModule.identifyUser(email, userName, id); // then - verify(Instabug.class,times(1)); - Instabug.identifyUser(userName, email); + mockInstabug.verify(() -> Instabug.identifyUser(userName, email, id)); + } + + @Test + public void testIdentifyUserWithId() { + // given + + String email = "sali@instabug.com"; + String userName = "salmaali"; + String id = "salmaali"; + // when + rnModule.identifyUser(email, userName, id); + // then + mockInstabug.verify(() -> Instabug.identifyUser(userName, email, id)); } @Test diff --git a/examples/default/ios/InstabugTests/InstabugSampleTests.m b/examples/default/ios/InstabugTests/InstabugSampleTests.m index 05e085ee3..6336ead72 100644 --- a/examples/default/ios/InstabugTests/InstabugSampleTests.m +++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m @@ -188,8 +188,19 @@ - (void)testIdentifyUser { NSString *name = @"this is my name"; OCMStub([mock identifyUserWithEmail:email name:name]); - [self.instabugBridge identifyUser:email name:name]; - OCMVerify([mock identifyUserWithEmail:email name:name]); + [self.instabugBridge identifyUser:email name:name userId:nil]; + OCMVerify([mock identifyUserWithID:nil email:email name:name]); +} + +- (void)testIdentifyUserWithID { + id mock = OCMClassMock([Instabug class]); + NSString *email = @"em@il.com"; + NSString *name = @"this is my name"; + NSString *userId = @"this is my id"; + + OCMStub([mock identifyUserWithID:userId email:email name:name]); + [self.instabugBridge identifyUser:email name:name userId:userId]; + OCMVerify([mock identifyUserWithID:userId email:email name:name]); } - (void)testLogOut { diff --git a/ios/RNInstabug/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h index 24baf146a..430429c90 100644 --- a/ios/RNInstabug/InstabugReactBridge.h +++ b/ios/RNInstabug/InstabugReactBridge.h @@ -49,7 +49,7 @@ - (void)setString:(NSString *)value toKey:(NSString *)key; -- (void)identifyUser:(NSString *)email name:(NSString *)name; +- (void)identifyUser:(NSString *)email name:(NSString *)name userId:(nullable NSString *)userId; - (void)logOut; diff --git a/ios/RNInstabug/InstabugReactBridge.m b/ios/RNInstabug/InstabugReactBridge.m index ed512fe32..785e67dfe 100644 --- a/ios/RNInstabug/InstabugReactBridge.m +++ b/ios/RNInstabug/InstabugReactBridge.m @@ -191,8 +191,8 @@ - (dispatch_queue_t)methodQueue { [Instabug clearFileAttachments]; } -RCT_EXPORT_METHOD(identifyUser:(NSString *)email name:(NSString *)name) { - [Instabug identifyUserWithEmail:email name:name]; +RCT_EXPORT_METHOD(identifyUser:(NSString *)email name:(NSString *)name userId:(nullable NSString *)userId) { + [Instabug identifyUserWithID:userId email:email name:name]; } RCT_EXPORT_METHOD(logOut) { diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index cf0debc9a..c04d5fa6f 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -196,15 +196,16 @@ export const setString = (key: StringKey, string: string) => { }; /** - * Sets the default value of the user's email and hides the email field from the reporting UI + * Sets the default value of the user's email and ID and hides the email field from the reporting UI * and set the user's name to be included with all reports. * It also reset the chats on device to that email and removes user attributes, * user data and completed surveys. * @param email Email address to be set as the user's email. * @param name Name of the user to be set. + * @param [id] ID of the user to be set. */ -export const identifyUser = (email: string, name: string) => { - NativeInstabug.identifyUser(email, name); +export const identifyUser = (email: string, name: string, id?: string) => { + NativeInstabug.identifyUser(email, name, id); }; /** diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts index b8b1d912f..83e81ecc6 100644 --- a/src/native/NativeInstabug.ts +++ b/src/native/NativeInstabug.ts @@ -62,7 +62,7 @@ export interface InstabugNativeModule extends NativeModule { clearLogs(): void; // User APIs // - identifyUser(email: string, name: string): void; + identifyUser(email: string, name: string, id?: string): void; logOut(): void; logUserEvent(name: string): void; setUserData(data: string): void; diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index c8019c1ea..84aa01b52 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -409,7 +409,17 @@ describe('Instabug Module', () => { Instabug.identifyUser(email, name); expect(NativeInstabug.identifyUser).toBeCalledTimes(1); - expect(NativeInstabug.identifyUser).toBeCalledWith(email, name); + expect(NativeInstabug.identifyUser).toBeCalledWith(email, name, undefined); + }); + + it('identifyUser when id is defined should call the native method identifyUser', () => { + const email = 'foo@instabug.com'; + const name = 'Instabug'; + const id = 'instabug-id'; + Instabug.identifyUser(email, name, id); + + expect(NativeInstabug.identifyUser).toBeCalledTimes(1); + expect(NativeInstabug.identifyUser).toBeCalledWith(email, name, id); }); it('should call the native method logOut', () => { From ad8d9c2875e787728dc7a63ffc72dd9e9fe9388c Mon Sep 17 00:00:00 2001 From: ahmed alaa <154802748+ahmedAlaaInstabug@users.noreply.github.com> Date: Mon, 5 Feb 2024 20:40:45 +0200 Subject: [PATCH 06/16] ci: replace d11 cluster url in UploadSourcemaps (#1122) --- .circleci/config.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.circleci/config.yml b/.circleci/config.yml index f677b4bd7..e168a097f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -301,6 +301,9 @@ jobs: - search_and_replace: file: package.json replace-pattern: 's/instabug-reactnative/@instabug\/instabug-reactnative-dream11/g' + - search_and_replace: + file: cli/UploadSourcemaps.ts + replace-pattern: 's/api.instabug.com\/api\/sdk/st001012dream11.instabug.com\/api\/sdk/g' - search_and_replace: file: android/native.gradle replace-pattern: 's/com\.instabug\.library:instabug:/com.instabug.library-dream11:instabug:/g' @@ -421,9 +424,6 @@ workflows: - hold_release_d11: requires: *release_dependencies type: approval - filters: - branches: - only: master - publish: requires: - hold_publish @@ -439,6 +439,3 @@ workflows: - release_d11: requires: - hold_release_d11 - filters: - branches: - only: master From 0942b38087e2a80eae53cb73870916944c0745d5 Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud <68241710+a7medev@users.noreply.github.com> Date: Mon, 5 Feb 2024 21:20:48 +0200 Subject: [PATCH 07/16] fix(android): resolve private views through UI manager directly (#1121) --- CHANGELOG.md | 4 ++ .../RNInstabugReactnativeModule.java | 55 ++++++++++--------- 2 files changed, 33 insertions(+), 26 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d01016490..2c001da64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,10 @@ - Support user identification using ID ([#1115](https://github.com/Instabug/Instabug-React-Native/pull/1115)) +### Fixed + +- Fix an Android `NullPointerException` crash in private views APIs ([#1121](https://github.com/Instabug/Instabug-React-Native/pull/1121)), closes [#514](https://github.com/Instabug/Instabug-React-Native/issues/514). + ## [12.6.0](https://github.com/Instabug/Instabug-React-Native/compare/v12.5.0...v12.6.0) (January 14, 2024) ### Changed diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index 57bcf1142..6ca6c3719 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -7,6 +7,8 @@ import android.net.Uri; import android.view.View; +import androidx.annotation.UiThread; + import com.facebook.react.bridge.Arguments; import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.Promise; @@ -17,8 +19,6 @@ import com.facebook.react.bridge.WritableMap; import com.facebook.react.bridge.WritableNativeArray; import com.facebook.react.bridge.WritableNativeMap; -import com.facebook.react.uimanager.NativeViewHierarchyManager; -import com.facebook.react.uimanager.UIBlock; import com.facebook.react.uimanager.UIManagerModule; import com.instabug.library.Feature; import com.instabug.library.Instabug; @@ -899,24 +899,32 @@ public void networkLog(String jsonObject) throws JSONException { networkLog.insert(); } + @UiThread + @Nullable + private View resolveReactView(final int reactTag) { + final ReactApplicationContext reactContext = getReactApplicationContext(); + final UIManagerModule uiManagerModule = reactContext.getNativeModule(UIManagerModule.class); + + if (uiManagerModule == null) { + return null; + } + + return uiManagerModule.resolveView(reactTag); + } + @ReactMethod public void addPrivateView(final int reactTag) { MainThreadHandler.runOnMainThread(new Runnable() { @Override public void run() { - UIManagerModule uiManagerModule = getReactApplicationContext().getNativeModule(UIManagerModule.class); - uiManagerModule.prependUIBlock(new UIBlock() { - @Override - public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { - try { - final View view = nativeViewHierarchyManager.resolveView(reactTag); - Instabug.addPrivateViews(view); - } catch(Exception e) { - e.printStackTrace(); - } - } - }); + try { + final View view = resolveReactView(reactTag); + + Instabug.addPrivateViews(view); + } catch (Exception e) { + e.printStackTrace(); + } } }); } @@ -926,18 +934,13 @@ public void removePrivateView(final int reactTag) { MainThreadHandler.runOnMainThread(new Runnable() { @Override public void run() { - UIManagerModule uiManagerModule = getReactApplicationContext().getNativeModule(UIManagerModule.class); - uiManagerModule.prependUIBlock(new UIBlock() { - @Override - public void execute(NativeViewHierarchyManager nativeViewHierarchyManager) { - try { - final View view = nativeViewHierarchyManager.resolveView(reactTag); - Instabug.removePrivateViews(view); - } catch(Exception e) { - e.printStackTrace(); - } - } - }); + try { + final View view = resolveReactView(reactTag); + + Instabug.removePrivateViews(view); + } catch (Exception e) { + e.printStackTrace(); + } } }); } From 35013f65c2c99c4a36a220e6fa50f9ef4ca6b4af Mon Sep 17 00:00:00 2001 From: Ahmed Mahmoud <68241710+a7medev@users.noreply.github.com> Date: Tue, 6 Feb 2024 14:48:59 +0200 Subject: [PATCH 08/16] feat: support switching to native network interception (#1120) --- .../RNInstabugReactnativeModule.java | 1 + .../ios/InstabugTests/InstabugSampleTests.m | 5 ++-- .../ios/InstabugTests/RNInstabugTests.m | 13 ++++++++ ios/RNInstabug/InstabugReactBridge.h | 2 +- ios/RNInstabug/InstabugReactBridge.m | 4 ++- ios/RNInstabug/RNInstabug.h | 8 +++++ ios/RNInstabug/RNInstabug.m | 21 ++++++++++--- src/models/InstabugConfig.ts | 13 +++++++- src/modules/Instabug.ts | 10 ++++++- src/native/NativeInstabug.ts | 1 + src/utils/Enums.ts | 8 +++++ test/mocks/mockNetworkLogger.ts | 1 + test/modules/Instabug.spec.ts | 30 +++++++++++++++++++ 13 files changed, 107 insertions(+), 10 deletions(-) create mode 100644 test/mocks/mockNetworkLogger.ts diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java index 6ca6c3719..32bf02a30 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugReactnativeModule.java @@ -127,6 +127,7 @@ public void init( final String token, final ReadableArray invocationEventValues, final String logLevel, + final boolean useNativeNetworkInterception, @Nullable final String codePushVersion ) { MainThreadHandler.runOnMainThread(new Runnable() { diff --git a/examples/default/ios/InstabugTests/InstabugSampleTests.m b/examples/default/ios/InstabugTests/InstabugSampleTests.m index 6336ead72..1b8183a06 100644 --- a/examples/default/ios/InstabugTests/InstabugSampleTests.m +++ b/examples/default/ios/InstabugTests/InstabugSampleTests.m @@ -70,14 +70,15 @@ - (void)testInit { NSString *appToken = @"app_token"; NSString *codePushVersion = @"1.0.0(1)"; NSArray *invocationEvents = [NSArray arrayWithObjects:[NSNumber numberWithInteger:floatingButtonInvocationEvent], nil]; + BOOL useNativeNetworkInterception = YES; IBGSDKDebugLogsLevel sdkDebugLogsLevel = IBGSDKDebugLogsLevelDebug; OCMStub([mock setCodePushVersion:codePushVersion]); - [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel codePushVersion:codePushVersion]; + [self.instabugBridge init:appToken invocationEvents:invocationEvents debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception codePushVersion:codePushVersion]; OCMVerify([mock setCodePushVersion:codePushVersion]); - OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel]); + OCMVerify([self.mRNInstabug initWithToken:appToken invocationEvents:floatingButtonInvocationEvent debugLogsLevel:sdkDebugLogsLevel useNativeNetworkInterception:useNativeNetworkInterception]); } - (void)testSetUserData { diff --git a/examples/default/ios/InstabugTests/RNInstabugTests.m b/examples/default/ios/InstabugTests/RNInstabugTests.m index d34c17abf..0df2fd843 100644 --- a/examples/default/ios/InstabugTests/RNInstabugTests.m +++ b/examples/default/ios/InstabugTests/RNInstabugTests.m @@ -41,6 +41,19 @@ - (void)testInitWithoutLogsLevel { OCMVerify([self.mIBGNetworkLogger setEnabled:YES]); } +- (void)testInitWithNativeNetworkInterception { + NSString *token = @"app-token"; + IBGInvocationEvent invocationEvents = IBGInvocationEventFloatingButton | IBGInvocationEventShake; + BOOL useNativeNetworkInterception = YES; + + [RNInstabug initWithToken:token invocationEvents:invocationEvents useNativeNetworkInterception:useNativeNetworkInterception]; + + OCMVerify([self.mInstabug startWithToken:token invocationEvents:invocationEvents]); + OCMVerify([self.mInstabug setCurrentPlatform:IBGPlatformReactNative]); + OCMVerify(never(), [self.mIBGNetworkLogger disableAutomaticCapturingOfNetworkLogs]); + OCMVerify([self.mIBGNetworkLogger setEnabled:YES]); +} + - (void)testInitWithLogsLevel { NSString *token = @"app-token"; IBGInvocationEvent invocationEvents = IBGInvocationEventFloatingButton | IBGInvocationEventShake; diff --git a/ios/RNInstabug/InstabugReactBridge.h b/ios/RNInstabug/InstabugReactBridge.h index 430429c90..f3eb9e81a 100644 --- a/ios/RNInstabug/InstabugReactBridge.h +++ b/ios/RNInstabug/InstabugReactBridge.h @@ -27,7 +27,7 @@ - (void)setEnabled:(BOOL)isEnabled; -- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel codePushVersion:(NSString *)codePushVersion; +- (void)init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion; - (void)setUserData:(NSString *)userData; diff --git a/ios/RNInstabug/InstabugReactBridge.m b/ios/RNInstabug/InstabugReactBridge.m index 785e67dfe..1ba365829 100644 --- a/ios/RNInstabug/InstabugReactBridge.m +++ b/ios/RNInstabug/InstabugReactBridge.m @@ -40,6 +40,7 @@ - (dispatch_queue_t)methodQueue { RCT_EXPORT_METHOD(init:(NSString *)token invocationEvents:(NSArray *)invocationEventsArray debugLogsLevel:(IBGSDKDebugLogsLevel)sdkDebugLogsLevel + useNativeNetworkInterception:(BOOL)useNativeNetworkInterception codePushVersion:(NSString *)codePushVersion) { IBGInvocationEvent invocationEvents = 0; @@ -51,7 +52,8 @@ - (dispatch_queue_t)methodQueue { [RNInstabug initWithToken:token invocationEvents:invocationEvents - debugLogsLevel:sdkDebugLogsLevel]; + debugLogsLevel:sdkDebugLogsLevel + useNativeNetworkInterception:useNativeNetworkInterception]; } RCT_EXPORT_METHOD(setReproStepsConfig:(IBGUserStepsMode)bugMode :(IBGUserStepsMode)crashMode:(IBGUserStepsMode)sessionReplayMode) { diff --git a/ios/RNInstabug/RNInstabug.h b/ios/RNInstabug/RNInstabug.h index e42b38844..91eaea84d 100644 --- a/ios/RNInstabug/RNInstabug.h +++ b/ios/RNInstabug/RNInstabug.h @@ -6,6 +6,14 @@ @interface RNInstabug : NSObject + (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents debugLogsLevel:(IBGSDKDebugLogsLevel)debugLogsLevel; + ++ (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents debugLogsLevel:(IBGSDKDebugLogsLevel)debugLogsLevel +useNativeNetworkInterception:(BOOL)useNativeNetworkInterception; + ++ (void)initWithToken:(NSString *)token + invocationEvents:(IBGInvocationEvent)invocationEvents +useNativeNetworkInterception:(BOOL)useNativeNetworkInterception; + + (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents; /** diff --git a/ios/RNInstabug/RNInstabug.m b/ios/RNInstabug/RNInstabug.m index 378835f72..275d0095b 100644 --- a/ios/RNInstabug/RNInstabug.m +++ b/ios/RNInstabug/RNInstabug.m @@ -13,15 +13,19 @@ + (void)reset { didInit = NO; } -+ (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents { ++ (void)initWithToken:(NSString *)token + invocationEvents:(IBGInvocationEvent)invocationEvents +useNativeNetworkInterception:(BOOL)useNativeNetworkInterception { didInit = YES; [Instabug setCurrentPlatform:IBGPlatformReactNative]; - // Disable automatic network logging in the iOS SDK to avoid duplicate network logs coming - // from both the iOS and React Native SDKs - [IBGNetworkLogger disableAutomaticCapturingOfNetworkLogs]; + if (!useNativeNetworkInterception) { + // Disable automatic network logging in the iOS SDK to avoid duplicate network logs coming + // from both the iOS and React Native SDKs + [IBGNetworkLogger disableAutomaticCapturingOfNetworkLogs]; + } [Instabug startWithToken:token invocationEvents:invocationEvents]; @@ -37,6 +41,15 @@ + (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)inv IBGAPM.hotAppLaunchEnabled = NO; } ++ (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents { + [self initWithToken:token invocationEvents:invocationEvents useNativeNetworkInterception:NO]; +} + ++ (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents debugLogsLevel:(IBGSDKDebugLogsLevel)debugLogsLevel useNativeNetworkInterception:(BOOL)useNativeNetworkInterception { + [Instabug setSdkDebugLogsLevel:debugLogsLevel]; + [self initWithToken:token invocationEvents:invocationEvents useNativeNetworkInterception:useNativeNetworkInterception]; +} + + (void)initWithToken:(NSString *)token invocationEvents:(IBGInvocationEvent)invocationEvents debugLogsLevel:(IBGSDKDebugLogsLevel)debugLogsLevel { diff --git a/src/models/InstabugConfig.ts b/src/models/InstabugConfig.ts index 0eda7a318..614ade892 100644 --- a/src/models/InstabugConfig.ts +++ b/src/models/InstabugConfig.ts @@ -1,4 +1,4 @@ -import type { InvocationEvent, LogLevel } from '../utils/Enums'; +import type { InvocationEvent, LogLevel, NetworkInterceptionMode } from '../utils/Enums'; export interface InstabugConfig { /** @@ -18,4 +18,15 @@ export interface InstabugConfig { * An optional code push version to be used for all reports. */ codePushVersion?: string; + + /** + * An optional network interception mode, this determines whether network interception + * is done in the JavaScript side or in the native Android and iOS SDK side. + * + * When set to `NetworkInterceptionMode.native`, configuring network logging + * should be done through native code not JavaScript (e.g. network request obfuscation). + * + * @default NetworkInterceptionMode.javascript + */ + networkInterceptionMode?: NetworkInterceptionMode; } diff --git a/src/modules/Instabug.ts b/src/modules/Instabug.ts index c04d5fa6f..781371c18 100644 --- a/src/modules/Instabug.ts +++ b/src/modules/Instabug.ts @@ -12,6 +12,7 @@ import { ColorTheme, Locale, LogLevel, + NetworkInterceptionMode, ReproStepsMode, StringKey, WelcomeMessageMode, @@ -61,12 +62,19 @@ function reportCurrentViewForAndroid(screenName: string | null) { export const init = (config: InstabugConfig) => { InstabugUtils.captureJsErrors(); captureUnhandledRejections(); - NetworkLogger.setEnabled(true); + + // Default networkInterceptionMode to JavaScript + config.networkInterceptionMode ??= NetworkInterceptionMode.javascript; + + if (config.networkInterceptionMode === NetworkInterceptionMode.javascript) { + NetworkLogger.setEnabled(true); + } NativeInstabug.init( config.token, config.invocationEvents, config.debugLogsLevel ?? LogLevel.error, + config.networkInterceptionMode === NetworkInterceptionMode.native, config.codePushVersion, ); diff --git a/src/native/NativeInstabug.ts b/src/native/NativeInstabug.ts index 83e81ecc6..f1adba7e9 100644 --- a/src/native/NativeInstabug.ts +++ b/src/native/NativeInstabug.ts @@ -23,6 +23,7 @@ export interface InstabugNativeModule extends NativeModule { token: string, invocationEvents: InvocationEvent[], debugLogsLevel: LogLevel, + useNativeNetworkInterception: boolean, codePushVersion?: string, ): void; show(): void; diff --git a/src/utils/Enums.ts b/src/utils/Enums.ts index 06878f37f..9fc86e5dc 100644 --- a/src/utils/Enums.ts +++ b/src/utils/Enums.ts @@ -24,6 +24,14 @@ export enum InvocationEvent { floatingButton = constants.invocationEventFloatingButton, } +/** + * The network interceptor to use. + */ +export enum NetworkInterceptionMode { + javascript, + native, +} + /** * Options added while invoking bug reporting. */ diff --git a/test/mocks/mockNetworkLogger.ts b/test/mocks/mockNetworkLogger.ts new file mode 100644 index 000000000..0eaed26e0 --- /dev/null +++ b/test/mocks/mockNetworkLogger.ts @@ -0,0 +1 @@ +jest.mock('../../src/modules/NetworkLogger'); diff --git a/test/modules/Instabug.spec.ts b/test/modules/Instabug.spec.ts index 84aa01b52..a78e141a1 100644 --- a/test/modules/Instabug.spec.ts +++ b/test/modules/Instabug.spec.ts @@ -1,4 +1,5 @@ import '../mocks/mockInstabugUtils'; +import '../mocks/mockNetworkLogger'; import { Platform, findNodeHandle, processColor } from 'react-native'; @@ -7,12 +8,14 @@ import waitForExpect from 'wait-for-expect'; import Report from '../../src/models/Report'; import * as Instabug from '../../src/modules/Instabug'; +import * as NetworkLogger from '../../src/modules/NetworkLogger'; import { NativeEvents, NativeInstabug, emitter } from '../../src/native/NativeInstabug'; import { ColorTheme, InvocationEvent, Locale, LogLevel, + NetworkInterceptionMode, ReproStepsMode, StringKey, WelcomeMessageMode, @@ -239,13 +242,40 @@ describe('Instabug Module', () => { debugLogsLevel: LogLevel.debug, codePushVersion: '1.1.0', }; + const usesNativeNetworkInterception = false; + + Instabug.init(instabugConfig); + + expect(NetworkLogger.setEnabled).toBeCalledWith(true); + expect(NativeInstabug.init).toBeCalledTimes(1); + expect(NativeInstabug.init).toBeCalledWith( + instabugConfig.token, + instabugConfig.invocationEvents, + instabugConfig.debugLogsLevel, + usesNativeNetworkInterception, + instabugConfig.codePushVersion, + ); + }); + + it('init should disable JavaScript interceptor when using native interception mode', () => { + const instabugConfig = { + token: 'some-token', + invocationEvents: [InvocationEvent.floatingButton, InvocationEvent.shake], + debugLogsLevel: LogLevel.debug, + networkInterceptionMode: NetworkInterceptionMode.native, + codePushVersion: '1.1.0', + }; + Instabug.init(instabugConfig); + expect(NetworkLogger.setEnabled).not.toBeCalled(); expect(NativeInstabug.init).toBeCalledTimes(1); expect(NativeInstabug.init).toBeCalledWith( instabugConfig.token, instabugConfig.invocationEvents, instabugConfig.debugLogsLevel, + // usesNativeNetworkInterception should be true when using native interception mode + true, instabugConfig.codePushVersion, ); }); From ad2fcc527956fe983c276f95514c9bf0ee6ba1f6 Mon Sep 17 00:00:00 2001 From: AbdElHamid Nasser Date: Sun, 14 Jan 2024 21:26:22 +0200 Subject: [PATCH 09/16] feat(example): Add more sdk crashes buttons --- .../RNInstabugCrashReportingModule.java | 121 ++++++++++++---- .../src/components/PlatformListTie.tsx | 37 +++++ .../src/screens/CrashReportingScreen.tsx | 134 +++++++++++++++--- ios/RNInstabug/InstabugCrashReportingBridge.h | 4 + ios/RNInstabug/InstabugCrashReportingBridge.m | 48 +++++++ src/native/NativeCrashReporting.ts | 5 + 6 files changed, 303 insertions(+), 46 deletions(-) create mode 100644 examples/default/src/components/PlatformListTie.tsx diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java index 8ac7d038b..9baa868a8 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java @@ -7,6 +7,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.instabug.crash.CrashReporting; +import com.instabug.crash.models.IBGNonFatalException; import com.instabug.library.Feature; import com.instabug.reactlibrary.utils.MainThreadHandler; @@ -14,6 +15,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -57,8 +61,8 @@ public void run() { * Send unhandled JS error object * * @param exceptionObject Exception object to be sent to Instabug's servers - * @param promise This makes sure that the RN side crashes the app only after the Android SDK - * finishes processing/handling the crash. + * @param promise This makes sure that the RN side crashes the app only after the Android SDK + * finishes processing/handling the crash. */ @ReactMethod public void sendJSCrash(final String exceptionObject, final Promise promise) { @@ -90,29 +94,96 @@ public void sendHandledJSCrash(final String exceptionObject) { } } - private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { - MainThreadHandler.runOnMainThread(new Runnable() { - @Override - public void run() { - try { - Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); - if (method != null) { - method.invoke(null, exceptionObject, isHandled); - RNInstabugReactnativeModule.clearCurrentReport(); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } finally { - if (onComplete != null) { - onComplete.run(); - } - } - } - }); + @ReactMethod + public void sendNativeNonFatal(final String exceptionObject) { + final IBGNonFatalException exception = new IBGNonFatalException.Builder(new IllegalStateException("Test exception")) + .build(); + CrashReporting.report(exception); + + } + + @ReactMethod + public void sendNativeFatalCrash() { + throw new IllegalStateException("Unhandled IllegalStateException from Instabug Test App"); + } + + @ReactMethod + public void sendANR() { + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendFatalHang() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendOOM() { + oomCrash(); + } + + private void oomCrash() { + new Thread(() -> { + List stringList = new ArrayList<>(); + for (int i = 0; i < 1_000_000; i++) { + stringList.add(getRandomString(10_000)); + } + }).start(); + } + + private String getRandomString(int length) { + List charset = new ArrayList<>(); + for (char ch = 'a'; ch <= 'z'; ch++) { + charset.add(ch); + } + for (char ch = 'A'; ch <= 'Z'; ch++) { + charset.add(ch); + } + for (char ch = '0'; ch <= '9'; ch++) { + charset.add(ch); + } + + StringBuilder randomString = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + char randomChar = charset.get(random.nextInt(charset.size())); + randomString.append(randomChar); + } + + return randomString.toString(); + } + + private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); + if (method != null) { + method.invoke(null, exceptionObject, isHandled); + RNInstabugReactnativeModule.clearCurrentReport(); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } finally { + if (onComplete != null) { + onComplete.run(); + } + } + } + }); } } diff --git a/examples/default/src/components/PlatformListTie.tsx b/examples/default/src/components/PlatformListTie.tsx new file mode 100644 index 000000000..1bf1fe6e7 --- /dev/null +++ b/examples/default/src/components/PlatformListTie.tsx @@ -0,0 +1,37 @@ +import React, { PropsWithChildren } from 'react'; + +import { Box, HStack, Pressable, Text } from 'native-base'; +import { Platform } from 'react-native'; + +interface PlatformListTileProps extends PropsWithChildren { + title: string; + onPress?: () => void; + platform?: 'ios' | 'android'; +} + +export const PlatformListTile: React.FC = ({ + title, + onPress, + platform, + children, +}) => { + if (Platform.OS === platform || !platform) { + return ( + + + {title} + {children} + + + ); + } + return null; +}; diff --git a/examples/default/src/screens/CrashReportingScreen.tsx b/examples/default/src/screens/CrashReportingScreen.tsx index 3d805185e..54449f16f 100644 --- a/examples/default/src/screens/CrashReportingScreen.tsx +++ b/examples/default/src/screens/CrashReportingScreen.tsx @@ -1,34 +1,126 @@ import React from 'react'; -import { Alert } from 'react-native'; +import { Alert, ScrollView, Text } from 'react-native'; import { CrashReporting } from 'instabug-reactnative'; import { ListTile } from '../components/ListTile'; import { Screen } from '../components/Screen'; +import { Section } from '../components/Section'; +import { NativeCrashReporting } from '../../../../src/native/NativeCrashReporting'; +import { PlatformListTile } from '../components/PlatformListTie'; export const CrashReportingScreen: React.FC = () => { + function throwHandledException(error: Error) { + try { + if (!error.message) { + const appName = 'Instabug Test App'; + error.message = `Handled ${error.name} From ${appName}`; + } + throw error; + } catch (err) { + if (err instanceof Error) { + CrashReporting.reportError(err).then(() => + Alert.alert(`Crash report for ${error.name} is Sent!`), + ); + } + } + } + + function throwUnhandledException(error: Error, isPromise: boolean = false) { + const appName = 'Instabug Test App'; + const rejectionType = isPromise ? 'Promise Rejection ' : ''; + const errorMessage = `Unhandled ${rejectionType}${error.name} from ${appName}`; + + if (!error.message) { + console.log(`IBG-CRSH | Error message: ${error.message}`); + error.message = errorMessage; + } + + if (isPromise) { + console.log('IBG-CRSH | Promise'); + Promise.reject(error).then(() => + Alert.alert(`Promise Rejection Crash report for ${error.name} is Sent!`), + ); + } else { + throw error; + } + } + return ( - { - try { - throw new Error('Handled Exception From Instabug Test App'); - } catch (err) { - if (err instanceof Error) { - CrashReporting.reportError(err); - Alert.alert('Crash report Sent!'); - } - } - }} - /> - { - Promise.reject(new Error('Unhandled Promise Rejection from Instabug Test App')); - Alert.alert('Crash report sent!'); - }} - /> + +
+ throwHandledException(new Error())} + /> + throwHandledException(new SyntaxError())} + /> + throwHandledException(new RangeError())} + /> + throwHandledException(new ReferenceError())} + /> + throwHandledException(new URIError())} + /> + NativeCrashReporting.sendNativeNonFatal()} + /> +
+
+ Fatal Crashes can only be tested in release mode + These buttons will crash the application. + throwUnhandledException(Error(), true)} + /> + throwUnhandledException(Error())} + /> + throwUnhandledException(new SyntaxError())} + /> + throwUnhandledException(new RangeError())} + /> + throwUnhandledException(new ReferenceError())} + /> + throwUnhandledException(new URIError())} + /> + NativeCrashReporting.sendNativeFatalCrash()} + /> + NativeCrashReporting.sendFatalHang()} + /> + NativeCrashReporting.sendANR()} + platform={'android'} + /> + NativeCrashReporting.sendOOM()} + /> +
+
); }; diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.h b/ios/RNInstabug/InstabugCrashReportingBridge.h index 5b4378185..97c5106fc 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.h +++ b/ios/RNInstabug/InstabugCrashReportingBridge.h @@ -7,5 +7,9 @@ - (void)setEnabled:(BOOL) isEnabled; - (void)sendJSCrash:(NSDictionary *)stackTrace; - (void)sendHandledJSCrash:(NSDictionary *)stackTrace; +- (void)sendNativeNonFatal; +- (void)sendNativeFatalCrash; +- (void)sendFatalHang; +- (void)sendOOM; @end diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.m b/ios/RNInstabug/InstabugCrashReportingBridge.m index df3a984e3..0cb08db77 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.m +++ b/ios/RNInstabug/InstabugCrashReportingBridge.m @@ -2,8 +2,21 @@ #import #import +@interface InstabugCrashReportingBridge() +@property (nonatomic, strong) NSMutableArray *oomBelly; +@property (nonatomic, strong) dispatch_queue_t serialQueue; +@end + @implementation InstabugCrashReportingBridge +- (instancetype)init { + self = [super init]; + if (self) { + self.serialQueue = dispatch_queue_create("QUEUE>SERIAL", DISPATCH_QUEUE_SERIAL); + } + return self; +} + - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } @@ -20,6 +33,24 @@ + (BOOL)requiresMainQueueSetup ]; } +- (void)oomCrash { + dispatch_async(self.serialQueue, ^{ + self.oomBelly = [NSMutableArray array]; + [UIApplication.sharedApplication beginBackgroundTaskWithName:@"OOM Crash" expirationHandler:nil]; + while (true) { + unsigned long dinnerLength = 1024 * 1024 * 10; + char *dinner = malloc(sizeof(char) * dinnerLength); + for (int i=0; i < dinnerLength; i++) + { + //write to each byte ensure that the memory pages are actually allocated + dinner[i] = '0'; + } + NSData *plate = [NSData dataWithBytesNoCopy:dinner length:dinnerLength freeWhenDone:YES]; + [self.oomBelly addObject:plate]; + } + }); +} + RCT_EXPORT_MODULE(IBGCrashReporting) RCT_EXPORT_METHOD(setEnabled: (BOOL) isEnabled) { @@ -52,6 +83,23 @@ + (BOOL)requiresMainQueueSetup }); } +RCT_EXPORT_METHOD(sendNativeNonFatal) { + IBGNonFatalException *nonFatalException = [IBGCrashReporting exception:[NSException exceptionWithName:@"native Handled NS Exception" reason:@"Test iOS Handled Crash" userInfo:@{@"Key": @"Value"}]]; + + [nonFatalException report]; +} + +RCT_EXPORT_METHOD(sendNativeFatalCrash) { + NSException *exception = [NSException exceptionWithName:@"native Unhandled NS Exception" reason:@"Test iOS Unhandled Crash" userInfo:nil]; + @throw exception; +} +RCT_EXPORT_METHOD(sendFatalHang) { + [NSThread sleepForTimeInterval:3.0f]; +} + +RCT_EXPORT_METHOD(sendOOM) { + [self oomCrash]; +} @synthesize description; diff --git a/src/native/NativeCrashReporting.ts b/src/native/NativeCrashReporting.ts index f1a8b85f4..5829c26b2 100644 --- a/src/native/NativeCrashReporting.ts +++ b/src/native/NativeCrashReporting.ts @@ -16,6 +16,11 @@ export interface CrashReportingNativeModule extends NativeModule { setEnabled(isEnabled: boolean): void; sendJSCrash(data: CrashData | string): Promise; sendHandledJSCrash(data: CrashData | string): Promise; + sendNativeNonFatal(): Promise; + sendNativeFatalCrash(): Promise; + sendFatalHang(): Promise; + sendANR(): Promise; + sendOOM(): Promise; } export const NativeCrashReporting = NativeModules.IBGCrashReporting; From 5c9b032ffe53e70e94bb6b12bd241b036afb2993 Mon Sep 17 00:00:00 2001 From: Abdelhamid Nasser <38096011+abdelhamid-f-nasser@users.noreply.github.com> Date: Wed, 31 Jan 2024 14:31:50 +0200 Subject: [PATCH 10/16] chore(android): ignore jetbrains ide run configurations (#1110) Jira ID: MOB-13736 From d0a3d403cec02ab52a00c6e087c846880d1f86d3 Mon Sep 17 00:00:00 2001 From: AbdElHamid Nasser Date: Sun, 14 Jan 2024 21:26:22 +0200 Subject: [PATCH 11/16] feat(example): Add more sdk crashes buttons --- .../RNInstabugCrashReportingModule.java | 121 ++++++++++++---- .../src/components/PlatformListTie.tsx | 37 +++++ .../src/screens/CrashReportingScreen.tsx | 134 +++++++++++++++--- ios/RNInstabug/InstabugCrashReportingBridge.h | 4 + ios/RNInstabug/InstabugCrashReportingBridge.m | 48 +++++++ src/native/NativeCrashReporting.ts | 5 + 6 files changed, 303 insertions(+), 46 deletions(-) create mode 100644 examples/default/src/components/PlatformListTie.tsx diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java index 8ac7d038b..9baa868a8 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java @@ -7,6 +7,7 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.instabug.crash.CrashReporting; +import com.instabug.crash.models.IBGNonFatalException; import com.instabug.library.Feature; import com.instabug.reactlibrary.utils.MainThreadHandler; @@ -14,6 +15,9 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -57,8 +61,8 @@ public void run() { * Send unhandled JS error object * * @param exceptionObject Exception object to be sent to Instabug's servers - * @param promise This makes sure that the RN side crashes the app only after the Android SDK - * finishes processing/handling the crash. + * @param promise This makes sure that the RN side crashes the app only after the Android SDK + * finishes processing/handling the crash. */ @ReactMethod public void sendJSCrash(final String exceptionObject, final Promise promise) { @@ -90,29 +94,96 @@ public void sendHandledJSCrash(final String exceptionObject) { } } - private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { - MainThreadHandler.runOnMainThread(new Runnable() { - @Override - public void run() { - try { - Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); - if (method != null) { - method.invoke(null, exceptionObject, isHandled); - RNInstabugReactnativeModule.clearCurrentReport(); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } finally { - if (onComplete != null) { - onComplete.run(); - } - } - } - }); + @ReactMethod + public void sendNativeNonFatal(final String exceptionObject) { + final IBGNonFatalException exception = new IBGNonFatalException.Builder(new IllegalStateException("Test exception")) + .build(); + CrashReporting.report(exception); + + } + + @ReactMethod + public void sendNativeFatalCrash() { + throw new IllegalStateException("Unhandled IllegalStateException from Instabug Test App"); + } + + @ReactMethod + public void sendANR() { + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendFatalHang() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendOOM() { + oomCrash(); + } + + private void oomCrash() { + new Thread(() -> { + List stringList = new ArrayList<>(); + for (int i = 0; i < 1_000_000; i++) { + stringList.add(getRandomString(10_000)); + } + }).start(); + } + + private String getRandomString(int length) { + List charset = new ArrayList<>(); + for (char ch = 'a'; ch <= 'z'; ch++) { + charset.add(ch); + } + for (char ch = 'A'; ch <= 'Z'; ch++) { + charset.add(ch); + } + for (char ch = '0'; ch <= '9'; ch++) { + charset.add(ch); + } + + StringBuilder randomString = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + char randomChar = charset.get(random.nextInt(charset.size())); + randomString.append(randomChar); + } + + return randomString.toString(); + } + + private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); + if (method != null) { + method.invoke(null, exceptionObject, isHandled); + RNInstabugReactnativeModule.clearCurrentReport(); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } finally { + if (onComplete != null) { + onComplete.run(); + } + } + } + }); } } diff --git a/examples/default/src/components/PlatformListTie.tsx b/examples/default/src/components/PlatformListTie.tsx new file mode 100644 index 000000000..1bf1fe6e7 --- /dev/null +++ b/examples/default/src/components/PlatformListTie.tsx @@ -0,0 +1,37 @@ +import React, { PropsWithChildren } from 'react'; + +import { Box, HStack, Pressable, Text } from 'native-base'; +import { Platform } from 'react-native'; + +interface PlatformListTileProps extends PropsWithChildren { + title: string; + onPress?: () => void; + platform?: 'ios' | 'android'; +} + +export const PlatformListTile: React.FC = ({ + title, + onPress, + platform, + children, +}) => { + if (Platform.OS === platform || !platform) { + return ( + + + {title} + {children} + + + ); + } + return null; +}; diff --git a/examples/default/src/screens/CrashReportingScreen.tsx b/examples/default/src/screens/CrashReportingScreen.tsx index 3d805185e..54449f16f 100644 --- a/examples/default/src/screens/CrashReportingScreen.tsx +++ b/examples/default/src/screens/CrashReportingScreen.tsx @@ -1,34 +1,126 @@ import React from 'react'; -import { Alert } from 'react-native'; +import { Alert, ScrollView, Text } from 'react-native'; import { CrashReporting } from 'instabug-reactnative'; import { ListTile } from '../components/ListTile'; import { Screen } from '../components/Screen'; +import { Section } from '../components/Section'; +import { NativeCrashReporting } from '../../../../src/native/NativeCrashReporting'; +import { PlatformListTile } from '../components/PlatformListTie'; export const CrashReportingScreen: React.FC = () => { + function throwHandledException(error: Error) { + try { + if (!error.message) { + const appName = 'Instabug Test App'; + error.message = `Handled ${error.name} From ${appName}`; + } + throw error; + } catch (err) { + if (err instanceof Error) { + CrashReporting.reportError(err).then(() => + Alert.alert(`Crash report for ${error.name} is Sent!`), + ); + } + } + } + + function throwUnhandledException(error: Error, isPromise: boolean = false) { + const appName = 'Instabug Test App'; + const rejectionType = isPromise ? 'Promise Rejection ' : ''; + const errorMessage = `Unhandled ${rejectionType}${error.name} from ${appName}`; + + if (!error.message) { + console.log(`IBG-CRSH | Error message: ${error.message}`); + error.message = errorMessage; + } + + if (isPromise) { + console.log('IBG-CRSH | Promise'); + Promise.reject(error).then(() => + Alert.alert(`Promise Rejection Crash report for ${error.name} is Sent!`), + ); + } else { + throw error; + } + } + return ( - { - try { - throw new Error('Handled Exception From Instabug Test App'); - } catch (err) { - if (err instanceof Error) { - CrashReporting.reportError(err); - Alert.alert('Crash report Sent!'); - } - } - }} - /> - { - Promise.reject(new Error('Unhandled Promise Rejection from Instabug Test App')); - Alert.alert('Crash report sent!'); - }} - /> + +
+ throwHandledException(new Error())} + /> + throwHandledException(new SyntaxError())} + /> + throwHandledException(new RangeError())} + /> + throwHandledException(new ReferenceError())} + /> + throwHandledException(new URIError())} + /> + NativeCrashReporting.sendNativeNonFatal()} + /> +
+
+ Fatal Crashes can only be tested in release mode + These buttons will crash the application. + throwUnhandledException(Error(), true)} + /> + throwUnhandledException(Error())} + /> + throwUnhandledException(new SyntaxError())} + /> + throwUnhandledException(new RangeError())} + /> + throwUnhandledException(new ReferenceError())} + /> + throwUnhandledException(new URIError())} + /> + NativeCrashReporting.sendNativeFatalCrash()} + /> + NativeCrashReporting.sendFatalHang()} + /> + NativeCrashReporting.sendANR()} + platform={'android'} + /> + NativeCrashReporting.sendOOM()} + /> +
+
); }; diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.h b/ios/RNInstabug/InstabugCrashReportingBridge.h index 5b4378185..97c5106fc 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.h +++ b/ios/RNInstabug/InstabugCrashReportingBridge.h @@ -7,5 +7,9 @@ - (void)setEnabled:(BOOL) isEnabled; - (void)sendJSCrash:(NSDictionary *)stackTrace; - (void)sendHandledJSCrash:(NSDictionary *)stackTrace; +- (void)sendNativeNonFatal; +- (void)sendNativeFatalCrash; +- (void)sendFatalHang; +- (void)sendOOM; @end diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.m b/ios/RNInstabug/InstabugCrashReportingBridge.m index df3a984e3..0cb08db77 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.m +++ b/ios/RNInstabug/InstabugCrashReportingBridge.m @@ -2,8 +2,21 @@ #import #import +@interface InstabugCrashReportingBridge() +@property (nonatomic, strong) NSMutableArray *oomBelly; +@property (nonatomic, strong) dispatch_queue_t serialQueue; +@end + @implementation InstabugCrashReportingBridge +- (instancetype)init { + self = [super init]; + if (self) { + self.serialQueue = dispatch_queue_create("QUEUE>SERIAL", DISPATCH_QUEUE_SERIAL); + } + return self; +} + - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } @@ -20,6 +33,24 @@ + (BOOL)requiresMainQueueSetup ]; } +- (void)oomCrash { + dispatch_async(self.serialQueue, ^{ + self.oomBelly = [NSMutableArray array]; + [UIApplication.sharedApplication beginBackgroundTaskWithName:@"OOM Crash" expirationHandler:nil]; + while (true) { + unsigned long dinnerLength = 1024 * 1024 * 10; + char *dinner = malloc(sizeof(char) * dinnerLength); + for (int i=0; i < dinnerLength; i++) + { + //write to each byte ensure that the memory pages are actually allocated + dinner[i] = '0'; + } + NSData *plate = [NSData dataWithBytesNoCopy:dinner length:dinnerLength freeWhenDone:YES]; + [self.oomBelly addObject:plate]; + } + }); +} + RCT_EXPORT_MODULE(IBGCrashReporting) RCT_EXPORT_METHOD(setEnabled: (BOOL) isEnabled) { @@ -52,6 +83,23 @@ + (BOOL)requiresMainQueueSetup }); } +RCT_EXPORT_METHOD(sendNativeNonFatal) { + IBGNonFatalException *nonFatalException = [IBGCrashReporting exception:[NSException exceptionWithName:@"native Handled NS Exception" reason:@"Test iOS Handled Crash" userInfo:@{@"Key": @"Value"}]]; + + [nonFatalException report]; +} + +RCT_EXPORT_METHOD(sendNativeFatalCrash) { + NSException *exception = [NSException exceptionWithName:@"native Unhandled NS Exception" reason:@"Test iOS Unhandled Crash" userInfo:nil]; + @throw exception; +} +RCT_EXPORT_METHOD(sendFatalHang) { + [NSThread sleepForTimeInterval:3.0f]; +} + +RCT_EXPORT_METHOD(sendOOM) { + [self oomCrash]; +} @synthesize description; diff --git a/src/native/NativeCrashReporting.ts b/src/native/NativeCrashReporting.ts index f1a8b85f4..5829c26b2 100644 --- a/src/native/NativeCrashReporting.ts +++ b/src/native/NativeCrashReporting.ts @@ -16,6 +16,11 @@ export interface CrashReportingNativeModule extends NativeModule { setEnabled(isEnabled: boolean): void; sendJSCrash(data: CrashData | string): Promise; sendHandledJSCrash(data: CrashData | string): Promise; + sendNativeNonFatal(): Promise; + sendNativeFatalCrash(): Promise; + sendFatalHang(): Promise; + sendANR(): Promise; + sendOOM(): Promise; } export const NativeCrashReporting = NativeModules.IBGCrashReporting; From 93100a996bfacc699e94ab648b842e1b6b4f43fc Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 11 Feb 2024 18:31:46 +0200 Subject: [PATCH 12/16] fix dev merge issue --- .../user-steps/BasicComponentsScreen.tsx | 148 ++++++++++++++++-- 1 file changed, 137 insertions(+), 11 deletions(-) diff --git a/examples/default/src/screens/user-steps/BasicComponentsScreen.tsx b/examples/default/src/screens/user-steps/BasicComponentsScreen.tsx index 16aa55b8c..6a3ded568 100644 --- a/examples/default/src/screens/user-steps/BasicComponentsScreen.tsx +++ b/examples/default/src/screens/user-steps/BasicComponentsScreen.tsx @@ -1,4 +1,4 @@ -import React, { useState } from 'react'; +import React, { useState, useRef } from 'react'; import { Alert, Button, @@ -10,24 +10,41 @@ import { Switch, useWindowDimensions, ActivityIndicator, + View, + TextInput, } from 'react-native'; import Slider from '@react-native-community/slider'; import { Center, HStack, ScrollView, VStack } from 'native-base'; +import Instabug from 'instabug-reactnative'; import { Screen } from '../../components/Screen'; import { Section } from '../../components/Section'; import { nativeBaseTheme } from '../../theme/nativeBaseTheme'; +import Icon from 'react-native-vector-icons/Ionicons'; import { InputField } from '../../components/InputField'; /** - * A screen that demonstates the usage of user steps with basic React Native components. + * A screen that demonstrates the usage of user steps with basic React Native components. * * This specific screen doesn't use NativeBase in some parts since we need to focus on * capturing React Native provided components rather than implementations built on top of it. */ export const BasicComponentsScreen: React.FC = () => { - const [isSwitchOn, setIsSwitchOn] = useState(false); const { width } = useWindowDimensions(); + const [isSwitchOn, setIsSwitchOn] = useState(false); + const textRef = useRef(null); + const imageRef = useRef(null); + const textInputRef = useRef(null); + const buttonRef = useRef
{
- +
- + +
+ +
+
@@ -129,6 +254,7 @@ const styles = StyleSheet.create({ formControlStyles.formControl, { backgroundColor: nativeBaseTheme.colors.primary[600], + justifyContent: 'center', }, ]), }); From d60d8dd5ae3f5f65293045f0f6aeccdef9692268 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 13 Feb 2024 05:15:29 +0200 Subject: [PATCH 13/16] feat_add_crash_buttons --- .../RNInstabugCrashReportingModule.java | 58 ---------- .../react/example/MainApplication.java | 3 +- ...RNInstabugExampleCrashReportingModule.java | 105 ++++++++++++++++++ .../RNInstabugExampleReactnativePackage.java | 41 +++++++ .../InstabugExample.xcodeproj/project.pbxproj | 14 +++ .../InstabugCrashReportingTests.m | 6 +- examples/default/ios/Podfile.lock | 2 +- .../ios/native/CrashReportingExampleModule.h | 12 ++ .../ios/native/CrashReportingExampleModule.m | 77 +++++++++++++ .../src/native/NativeCrashReporting.ts | 13 +++ examples/default/src/native/NativePackage.ts | 9 ++ .../src/screens/CrashReportingScreen.tsx | 12 +- src/native/NativeCrashReporting.ts | 5 - 13 files changed, 282 insertions(+), 75 deletions(-) create mode 100644 examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleCrashReportingModule.java create mode 100644 examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleReactnativePackage.java create mode 100644 examples/default/ios/native/CrashReportingExampleModule.h create mode 100644 examples/default/ios/native/CrashReportingExampleModule.m create mode 100644 examples/default/src/native/NativeCrashReporting.ts create mode 100644 examples/default/src/native/NativePackage.ts diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java index 9baa868a8..5b65715df 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java @@ -102,64 +102,6 @@ public void sendNativeNonFatal(final String exceptionObject) { } - @ReactMethod - public void sendNativeFatalCrash() { - throw new IllegalStateException("Unhandled IllegalStateException from Instabug Test App"); - } - - @ReactMethod - public void sendANR() { - try { - Thread.sleep(20000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - @ReactMethod - public void sendFatalHang() { - try { - Thread.sleep(3000); - } catch (InterruptedException e) { - throw new RuntimeException(e); - } - } - - @ReactMethod - public void sendOOM() { - oomCrash(); - } - - private void oomCrash() { - new Thread(() -> { - List stringList = new ArrayList<>(); - for (int i = 0; i < 1_000_000; i++) { - stringList.add(getRandomString(10_000)); - } - }).start(); - } - - private String getRandomString(int length) { - List charset = new ArrayList<>(); - for (char ch = 'a'; ch <= 'z'; ch++) { - charset.add(ch); - } - for (char ch = 'A'; ch <= 'Z'; ch++) { - charset.add(ch); - } - for (char ch = '0'; ch <= '9'; ch++) { - charset.add(ch); - } - - StringBuilder randomString = new StringBuilder(); - Random random = new Random(); - for (int i = 0; i < length; i++) { - char randomChar = charset.get(random.nextInt(charset.size())); - randomString.append(randomChar); - } - - return randomString.toString(); - } private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { MainThreadHandler.runOnMainThread(new Runnable() { diff --git a/examples/default/android/app/src/main/java/com/instabug/react/example/MainApplication.java b/examples/default/android/app/src/main/java/com/instabug/react/example/MainApplication.java index 285c0dc84..a988f0a84 100644 --- a/examples/default/android/app/src/main/java/com/instabug/react/example/MainApplication.java +++ b/examples/default/android/app/src/main/java/com/instabug/react/example/MainApplication.java @@ -21,10 +21,9 @@ public boolean getUseDeveloperSupport() { @Override protected List getPackages() { - @SuppressWarnings("UnnecessaryLocalVariable") List packages = new PackageList(this).getPackages(); // Packages that cannot be autolinked yet can be added manually here, for example: - // packages.add(new MyReactNativePackage()); + packages.add(new RNInstabugExampleReactnativePackage()); return packages; } diff --git a/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleCrashReportingModule.java b/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleCrashReportingModule.java new file mode 100644 index 000000000..7f748ad9f --- /dev/null +++ b/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleCrashReportingModule.java @@ -0,0 +1,105 @@ +package com.instabug.react.example; + +import static com.instabug.reactlibrary.utils.InstabugUtil.getMethod; + +import com.facebook.react.bridge.Promise; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; +import com.instabug.crash.CrashReporting; +import com.instabug.crash.models.IBGNonFatalException; +import com.instabug.library.Feature; +import com.instabug.reactlibrary.RNInstabugReactnativeModule; +import com.instabug.reactlibrary.utils.MainThreadHandler; + +import org.json.JSONObject; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +public class RNInstabugExampleCrashReportingModule extends ReactContextBaseJavaModule { + + public RNInstabugExampleCrashReportingModule(ReactApplicationContext reactApplicationContext) { + super(reactApplicationContext); + } + + @Nonnull + @Override + public String getName() { + return "CrashReportingExampleModule"; + } + + @ReactMethod + public void sendNativeNonFatal(final String exceptionObject) { + final IBGNonFatalException exception = new IBGNonFatalException.Builder(new IllegalStateException("Test exception")) + .build(); + CrashReporting.report(exception); + + } + + @ReactMethod + public void sendNativeFatalCrash() { + throw new IllegalStateException("Unhandled IllegalStateException from Instabug Test App"); + } + + @ReactMethod + public void sendANR() { + try { + Thread.sleep(20000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendFatalHang() { + try { + Thread.sleep(3000); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + @ReactMethod + public void sendOOM() { + oomCrash(); + } + + private void oomCrash() { + new Thread(() -> { + List stringList = new ArrayList<>(); + for (int i = 0; i < 1_000_000; i++) { + stringList.add(getRandomString(10_000)); + } + }).start(); + } + + private String getRandomString(int length) { + List charset = new ArrayList<>(); + for (char ch = 'a'; ch <= 'z'; ch++) { + charset.add(ch); + } + for (char ch = 'A'; ch <= 'Z'; ch++) { + charset.add(ch); + } + for (char ch = '0'; ch <= '9'; ch++) { + charset.add(ch); + } + + StringBuilder randomString = new StringBuilder(); + Random random = new Random(); + for (int i = 0; i < length; i++) { + char randomChar = charset.get(random.nextInt(charset.size())); + randomString.append(randomChar); + } + + return randomString.toString(); + } + +} diff --git a/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleReactnativePackage.java b/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleReactnativePackage.java new file mode 100644 index 000000000..304ab6870 --- /dev/null +++ b/examples/default/android/app/src/main/java/com/instabug/react/example/RNInstabugExampleReactnativePackage.java @@ -0,0 +1,41 @@ +package com.instabug.react.example; + +import androidx.annotation.NonNull; + +import com.facebook.react.ReactPackage; +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.uimanager.ViewManager; +import com.instabug.reactlibrary.RNInstabugAPMModule; +import com.instabug.reactlibrary.RNInstabugBugReportingModule; +import com.instabug.reactlibrary.RNInstabugCrashReportingModule; +import com.instabug.reactlibrary.RNInstabugFeatureRequestsModule; +import com.instabug.reactlibrary.RNInstabugReactnativeModule; +import com.instabug.reactlibrary.RNInstabugRepliesModule; +import com.instabug.reactlibrary.RNInstabugSessionReplayModule; +import com.instabug.reactlibrary.RNInstabugSurveysModule; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; + +public class RNInstabugExampleReactnativePackage implements ReactPackage { + + private static final String TAG = RNInstabugExampleReactnativePackage.class.getSimpleName(); + + public RNInstabugExampleReactnativePackage() {} + + @NonNull + @Override + public List createNativeModules(@NonNull ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + modules.add(new RNInstabugExampleCrashReportingModule(reactContext)); + return modules; + } + + @NonNull + @Override + public List createViewManagers(@NonNull ReactApplicationContext reactContext) { + return Collections.emptyList(); + } +} diff --git a/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj b/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj index f7632345b..32dd9b905 100644 --- a/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj +++ b/examples/default/ios/InstabugExample.xcodeproj/project.pbxproj @@ -12,6 +12,7 @@ 13B07FC11A68108700A75B9A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 13B07FB71A68108700A75B9A /* main.m */; }; 20E556262AC55766007416B1 /* InstabugSessionReplayTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 20E556252AC55766007416B1 /* InstabugSessionReplayTests.m */; }; 81AB9BB82411601600AC10FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */; }; + C3C8CCF379347A4DF9D2A39D /* CrashReportingExampleModule.m in Sources */ = {isa = PBXBuildFile; fileRef = C3C8C24386310A3120006604 /* CrashReportingExampleModule.m */; }; CC3DF88E2A1DFC9A003E9914 /* InstabugCrashReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3DF8852A1DFC99003E9914 /* InstabugCrashReportingTests.m */; }; CC3DF88F2A1DFC9A003E9914 /* InstabugBugReportingTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3DF8862A1DFC99003E9914 /* InstabugBugReportingTests.m */; }; CC3DF8902A1DFC9A003E9914 /* InstabugSampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = CC3DF8872A1DFC99003E9914 /* InstabugSampleTests.m */; }; @@ -51,6 +52,8 @@ 9A3D962AB03F97E25566779F /* Pods-InstabugExample.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugExample.debug.xcconfig"; path = "Target Support Files/Pods-InstabugExample/Pods-InstabugExample.debug.xcconfig"; sourceTree = ""; }; BAED0D0441A708AE2390E153 /* libPods-InstabugExample.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-InstabugExample.a"; sourceTree = BUILT_PRODUCTS_DIR; }; BD54B44E2DF85672BB2D4DEE /* Pods-InstabugExample.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-InstabugExample.release.xcconfig"; path = "Target Support Files/Pods-InstabugExample/Pods-InstabugExample.release.xcconfig"; sourceTree = ""; }; + C3C8C24386310A3120006604 /* CrashReportingExampleModule.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CrashReportingExampleModule.m; sourceTree = ""; }; + C3C8C784EADC037C5A752B94 /* CrashReportingExampleModule.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CrashReportingExampleModule.h; sourceTree = ""; }; CC3DF8852A1DFC99003E9914 /* InstabugCrashReportingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstabugCrashReportingTests.m; sourceTree = ""; }; CC3DF8862A1DFC99003E9914 /* InstabugBugReportingTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstabugBugReportingTests.m; sourceTree = ""; }; CC3DF8872A1DFC99003E9914 /* InstabugSampleTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = InstabugSampleTests.m; sourceTree = ""; }; @@ -121,6 +124,7 @@ 13B07FB61A68108700A75B9A /* Info.plist */, 81AB9BB72411601600AC10FF /* LaunchScreen.storyboard */, 13B07FB71A68108700A75B9A /* main.m */, + C3C8C1DDCEA91410F27A3683 /* native */, ); name = InstabugExample; sourceTree = ""; @@ -177,6 +181,15 @@ path = Pods; sourceTree = ""; }; + C3C8C1DDCEA91410F27A3683 /* native */ = { + isa = PBXGroup; + children = ( + C3C8C784EADC037C5A752B94 /* CrashReportingExampleModule.h */, + C3C8C24386310A3120006604 /* CrashReportingExampleModule.m */, + ); + path = native; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -463,6 +476,7 @@ files = ( 13B07FBC1A68108700A75B9A /* AppDelegate.mm in Sources */, 13B07FC11A68108700A75B9A /* main.m in Sources */, + C3C8CCF379347A4DF9D2A39D /* CrashReportingExampleModule.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m b/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m index 83f682cd3..a502b974f 100644 --- a/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m +++ b/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m @@ -1,15 +1,15 @@ #import #import "Instabug/Instabug.h" -#import "InstabugCrashReportingBridge.h" +#import "CrashReportingExampleModule.h" @interface InstabugCrashReportingTests : XCTestCase -@property (nonatomic, retain) InstabugCrashReportingBridge *bridge; +@property (nonatomic, retain) CrashReportingExampleModule *bridge; @end @implementation InstabugCrashReportingTests - (void)setUp { - self.bridge = [[InstabugCrashReportingBridge alloc] init]; + self.bridge = [[CrashReportingExampleModule alloc] init]; } - (void)testSetEnabled { diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock index 69b5bd961..c7312c70d 100644 --- a/examples/default/ios/Podfile.lock +++ b/examples/default/ios/Podfile.lock @@ -795,4 +795,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d169b4508f413ff5d69cdf38428960e0828e6282 -COCOAPODS: 1.12.0 +COCOAPODS: 1.14.3 diff --git a/examples/default/ios/native/CrashReportingExampleModule.h b/examples/default/ios/native/CrashReportingExampleModule.h new file mode 100644 index 000000000..d9b35437c --- /dev/null +++ b/examples/default/ios/native/CrashReportingExampleModule.h @@ -0,0 +1,12 @@ +#import +#import +#import + +@interface CrashReportingExampleModule : RCTEventEmitter + +- (void)sendNativeNonFatal; +- (void)sendNativeFatalCrash; +- (void)sendFatalHang; +- (void)sendOOM; + +@end diff --git a/examples/default/ios/native/CrashReportingExampleModule.m b/examples/default/ios/native/CrashReportingExampleModule.m new file mode 100644 index 000000000..b337da215 --- /dev/null +++ b/examples/default/ios/native/CrashReportingExampleModule.m @@ -0,0 +1,77 @@ +#import "CrashReportingExampleModule.h" +#import +#import + +@interface CrashReportingExampleModule() +@property (nonatomic, strong) NSMutableArray *oomBelly; +@property (nonatomic, strong) dispatch_queue_t serialQueue; +@end + +@implementation CrashReportingExampleModule + +- (instancetype)init { + self = [super init]; + if (self) { + self.serialQueue = dispatch_queue_create("QUEUE>SERIAL", DISPATCH_QUEUE_SERIAL); + } + return self; +} + +- (dispatch_queue_t)methodQueue { + return dispatch_get_main_queue(); +} + ++ (BOOL)requiresMainQueueSetup +{ + return NO; +} + + +- (void)oomCrash { + dispatch_async(self.serialQueue, ^{ + self.oomBelly = [NSMutableArray array]; + [UIApplication.sharedApplication beginBackgroundTaskWithName:@"OOM Crash" expirationHandler:nil]; + while (true) { + unsigned long dinnerLength = 1024 * 1024 * 10; + char *dinner = malloc(sizeof(char) * dinnerLength); + for (int i=0; i < dinnerLength; i++) + { + //write to each byte ensure that the memory pages are actually allocated + dinner[i] = '0'; + } + NSData *plate = [NSData dataWithBytesNoCopy:dinner length:dinnerLength freeWhenDone:YES]; + [self.oomBelly addObject:plate]; + } + }); +} + +RCT_EXPORT_MODULE(CrashReportingExampleModule) + + +RCT_EXPORT_METHOD(sendNativeNonFatal) { + IBGNonFatalException *nonFatalException = [IBGCrashReporting exception:[NSException exceptionWithName:@"native Handled NS Exception" reason:@"Test iOS Handled Crash" userInfo:@{@"Key": @"Value"}]]; + + [nonFatalException report]; +} + +RCT_EXPORT_METHOD(sendNativeFatalCrash) { + NSException *exception = [NSException exceptionWithName:@"native Unhandled NS Exception" reason:@"Test iOS Unhandled Crash" userInfo:nil]; + @throw exception; +} +RCT_EXPORT_METHOD(sendFatalHang) { + [NSThread sleepForTimeInterval:3.0f]; +} + +RCT_EXPORT_METHOD(sendOOM) { + [self oomCrash]; +} + +@synthesize description; + +@synthesize hash; + +@synthesize superclass; + +@end + + diff --git a/examples/default/src/native/NativeCrashReporting.ts b/examples/default/src/native/NativeCrashReporting.ts new file mode 100644 index 000000000..a64f4526d --- /dev/null +++ b/examples/default/src/native/NativeCrashReporting.ts @@ -0,0 +1,13 @@ +import type { NativeModule } from 'react-native'; + +import { NativeExampleModules } from './NativePackage'; + +export interface CrashReportingExampleNativeModule extends NativeModule { + sendNativeNonFatal(): Promise; + sendNativeFatalCrash(): Promise; + sendFatalHang(): Promise; + sendANR(): Promise; + sendOOM(): Promise; +} + +export const NativeExampleCrashReporting = NativeExampleModules.CrashReportingExampleModule; diff --git a/examples/default/src/native/NativePackage.ts b/examples/default/src/native/NativePackage.ts new file mode 100644 index 000000000..16b79b494 --- /dev/null +++ b/examples/default/src/native/NativePackage.ts @@ -0,0 +1,9 @@ +import { NativeModules as ReactNativeModules } from 'react-native'; + +import type { CrashReportingExampleNativeModule } from './NativeCrashReporting'; + +export interface InstabugExampleNativePackage { + CrashReportingExampleModule: CrashReportingExampleNativeModule; +} + +export const NativeExampleModules = ReactNativeModules as InstabugExampleNativePackage; diff --git a/examples/default/src/screens/CrashReportingScreen.tsx b/examples/default/src/screens/CrashReportingScreen.tsx index 54449f16f..b477cf18b 100644 --- a/examples/default/src/screens/CrashReportingScreen.tsx +++ b/examples/default/src/screens/CrashReportingScreen.tsx @@ -6,8 +6,8 @@ import { CrashReporting } from 'instabug-reactnative'; import { ListTile } from '../components/ListTile'; import { Screen } from '../components/Screen'; import { Section } from '../components/Section'; -import { NativeCrashReporting } from '../../../../src/native/NativeCrashReporting'; import { PlatformListTile } from '../components/PlatformListTie'; +import { NativeExampleCrashReporting } from '../native/NativeCrashReporting'; export const CrashReportingScreen: React.FC = () => { function throwHandledException(error: Error) { @@ -72,7 +72,7 @@ export const CrashReportingScreen: React.FC = () => { /> NativeCrashReporting.sendNativeNonFatal()} + onPress={() => NativeExampleCrashReporting.sendNativeNonFatal()} />
@@ -104,20 +104,20 @@ export const CrashReportingScreen: React.FC = () => { /> NativeCrashReporting.sendNativeFatalCrash()} + onPress={() => NativeExampleCrashReporting.sendNativeFatalCrash()} /> NativeCrashReporting.sendFatalHang()} + onPress={() => NativeExampleCrashReporting.sendFatalHang()} /> NativeCrashReporting.sendANR()} + onPress={() => NativeExampleCrashReporting.sendANR()} platform={'android'} /> NativeCrashReporting.sendOOM()} + onPress={() => NativeExampleCrashReporting.sendOOM()} />
diff --git a/src/native/NativeCrashReporting.ts b/src/native/NativeCrashReporting.ts index 5829c26b2..f1a8b85f4 100644 --- a/src/native/NativeCrashReporting.ts +++ b/src/native/NativeCrashReporting.ts @@ -16,11 +16,6 @@ export interface CrashReportingNativeModule extends NativeModule { setEnabled(isEnabled: boolean): void; sendJSCrash(data: CrashData | string): Promise; sendHandledJSCrash(data: CrashData | string): Promise; - sendNativeNonFatal(): Promise; - sendNativeFatalCrash(): Promise; - sendFatalHang(): Promise; - sendANR(): Promise; - sendOOM(): Promise; } export const NativeCrashReporting = NativeModules.IBGCrashReporting; From 904d06953811e4c93d6c2accc5d8635790ed501e Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 13 Feb 2024 05:19:05 +0200 Subject: [PATCH 14/16] feat_add_crash_buttons --- .../RNInstabugCrashReportingModule.java | 63 ++++++++----------- ios/RNInstabug/InstabugCrashReportingBridge.h | 4 -- ios/RNInstabug/InstabugCrashReportingBridge.m | 48 -------------- 3 files changed, 25 insertions(+), 90 deletions(-) diff --git a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java index 5b65715df..8ac7d038b 100644 --- a/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java +++ b/android/src/main/java/com/instabug/reactlibrary/RNInstabugCrashReportingModule.java @@ -7,7 +7,6 @@ import com.facebook.react.bridge.ReactContextBaseJavaModule; import com.facebook.react.bridge.ReactMethod; import com.instabug.crash.CrashReporting; -import com.instabug.crash.models.IBGNonFatalException; import com.instabug.library.Feature; import com.instabug.reactlibrary.utils.MainThreadHandler; @@ -15,9 +14,6 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.List; -import java.util.Random; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -61,8 +57,8 @@ public void run() { * Send unhandled JS error object * * @param exceptionObject Exception object to be sent to Instabug's servers - * @param promise This makes sure that the RN side crashes the app only after the Android SDK - * finishes processing/handling the crash. + * @param promise This makes sure that the RN side crashes the app only after the Android SDK + * finishes processing/handling the crash. */ @ReactMethod public void sendJSCrash(final String exceptionObject, final Promise promise) { @@ -94,38 +90,29 @@ public void sendHandledJSCrash(final String exceptionObject) { } } - @ReactMethod - public void sendNativeNonFatal(final String exceptionObject) { - final IBGNonFatalException exception = new IBGNonFatalException.Builder(new IllegalStateException("Test exception")) - .build(); - CrashReporting.report(exception); - - } - - - private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { - MainThreadHandler.runOnMainThread(new Runnable() { - @Override - public void run() { - try { - Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); - if (method != null) { - method.invoke(null, exceptionObject, isHandled); - RNInstabugReactnativeModule.clearCurrentReport(); - } - } catch (ClassNotFoundException e) { - e.printStackTrace(); - } catch (IllegalAccessException e) { - e.printStackTrace(); - } catch (InvocationTargetException e) { - e.printStackTrace(); - } finally { - if (onComplete != null) { - onComplete.run(); - } - } - } - }); + private void sendJSCrashByReflection(final JSONObject exceptionObject, final boolean isHandled, @Nullable final Runnable onComplete) { + MainThreadHandler.runOnMainThread(new Runnable() { + @Override + public void run() { + try { + Method method = getMethod(Class.forName("com.instabug.crash.CrashReporting"), "reportException", JSONObject.class, boolean.class); + if (method != null) { + method.invoke(null, exceptionObject, isHandled); + RNInstabugReactnativeModule.clearCurrentReport(); + } + } catch (ClassNotFoundException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } catch (InvocationTargetException e) { + e.printStackTrace(); + } finally { + if (onComplete != null) { + onComplete.run(); + } + } + } + }); } } diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.h b/ios/RNInstabug/InstabugCrashReportingBridge.h index 97c5106fc..5b4378185 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.h +++ b/ios/RNInstabug/InstabugCrashReportingBridge.h @@ -7,9 +7,5 @@ - (void)setEnabled:(BOOL) isEnabled; - (void)sendJSCrash:(NSDictionary *)stackTrace; - (void)sendHandledJSCrash:(NSDictionary *)stackTrace; -- (void)sendNativeNonFatal; -- (void)sendNativeFatalCrash; -- (void)sendFatalHang; -- (void)sendOOM; @end diff --git a/ios/RNInstabug/InstabugCrashReportingBridge.m b/ios/RNInstabug/InstabugCrashReportingBridge.m index 0cb08db77..df3a984e3 100644 --- a/ios/RNInstabug/InstabugCrashReportingBridge.m +++ b/ios/RNInstabug/InstabugCrashReportingBridge.m @@ -2,21 +2,8 @@ #import #import -@interface InstabugCrashReportingBridge() -@property (nonatomic, strong) NSMutableArray *oomBelly; -@property (nonatomic, strong) dispatch_queue_t serialQueue; -@end - @implementation InstabugCrashReportingBridge -- (instancetype)init { - self = [super init]; - if (self) { - self.serialQueue = dispatch_queue_create("QUEUE>SERIAL", DISPATCH_QUEUE_SERIAL); - } - return self; -} - - (dispatch_queue_t)methodQueue { return dispatch_get_main_queue(); } @@ -33,24 +20,6 @@ + (BOOL)requiresMainQueueSetup ]; } -- (void)oomCrash { - dispatch_async(self.serialQueue, ^{ - self.oomBelly = [NSMutableArray array]; - [UIApplication.sharedApplication beginBackgroundTaskWithName:@"OOM Crash" expirationHandler:nil]; - while (true) { - unsigned long dinnerLength = 1024 * 1024 * 10; - char *dinner = malloc(sizeof(char) * dinnerLength); - for (int i=0; i < dinnerLength; i++) - { - //write to each byte ensure that the memory pages are actually allocated - dinner[i] = '0'; - } - NSData *plate = [NSData dataWithBytesNoCopy:dinner length:dinnerLength freeWhenDone:YES]; - [self.oomBelly addObject:plate]; - } - }); -} - RCT_EXPORT_MODULE(IBGCrashReporting) RCT_EXPORT_METHOD(setEnabled: (BOOL) isEnabled) { @@ -83,23 +52,6 @@ - (void)oomCrash { }); } -RCT_EXPORT_METHOD(sendNativeNonFatal) { - IBGNonFatalException *nonFatalException = [IBGCrashReporting exception:[NSException exceptionWithName:@"native Handled NS Exception" reason:@"Test iOS Handled Crash" userInfo:@{@"Key": @"Value"}]]; - - [nonFatalException report]; -} - -RCT_EXPORT_METHOD(sendNativeFatalCrash) { - NSException *exception = [NSException exceptionWithName:@"native Unhandled NS Exception" reason:@"Test iOS Unhandled Crash" userInfo:nil]; - @throw exception; -} -RCT_EXPORT_METHOD(sendFatalHang) { - [NSThread sleepForTimeInterval:3.0f]; -} - -RCT_EXPORT_METHOD(sendOOM) { - [self oomCrash]; -} @synthesize description; From b4a202b5d57b8a01249cc466ca2f98d9dcce7561 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Tue, 13 Feb 2024 05:20:42 +0200 Subject: [PATCH 15/16] feat_add_crash_buttons --- .../default/ios/InstabugTests/InstabugCrashReportingTests.m | 6 +++--- examples/default/ios/Podfile.lock | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m b/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m index a502b974f..83f682cd3 100644 --- a/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m +++ b/examples/default/ios/InstabugTests/InstabugCrashReportingTests.m @@ -1,15 +1,15 @@ #import #import "Instabug/Instabug.h" -#import "CrashReportingExampleModule.h" +#import "InstabugCrashReportingBridge.h" @interface InstabugCrashReportingTests : XCTestCase -@property (nonatomic, retain) CrashReportingExampleModule *bridge; +@property (nonatomic, retain) InstabugCrashReportingBridge *bridge; @end @implementation InstabugCrashReportingTests - (void)setUp { - self.bridge = [[CrashReportingExampleModule alloc] init]; + self.bridge = [[InstabugCrashReportingBridge alloc] init]; } - (void)testSetEnabled { diff --git a/examples/default/ios/Podfile.lock b/examples/default/ios/Podfile.lock index c7312c70d..69b5bd961 100644 --- a/examples/default/ios/Podfile.lock +++ b/examples/default/ios/Podfile.lock @@ -795,4 +795,4 @@ SPEC CHECKSUMS: PODFILE CHECKSUM: d169b4508f413ff5d69cdf38428960e0828e6282 -COCOAPODS: 1.14.3 +COCOAPODS: 1.12.0 From fc3409a7e695988eaceeacb50935bf4ca125aa89 Mon Sep 17 00:00:00 2001 From: Ahmed alaa Date: Sun, 18 Feb 2024 14:13:32 +0200 Subject: [PATCH 16/16] fix: PlatformListTile typo name --- .../components/{PlatformListTie.tsx => PlatformListTile.tsx} | 0 examples/default/src/screens/CrashReportingScreen.tsx | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) rename examples/default/src/components/{PlatformListTie.tsx => PlatformListTile.tsx} (100%) diff --git a/examples/default/src/components/PlatformListTie.tsx b/examples/default/src/components/PlatformListTile.tsx similarity index 100% rename from examples/default/src/components/PlatformListTie.tsx rename to examples/default/src/components/PlatformListTile.tsx diff --git a/examples/default/src/screens/CrashReportingScreen.tsx b/examples/default/src/screens/CrashReportingScreen.tsx index b477cf18b..eeb1b6f18 100644 --- a/examples/default/src/screens/CrashReportingScreen.tsx +++ b/examples/default/src/screens/CrashReportingScreen.tsx @@ -6,7 +6,7 @@ import { CrashReporting } from 'instabug-reactnative'; import { ListTile } from '../components/ListTile'; import { Screen } from '../components/Screen'; import { Section } from '../components/Section'; -import { PlatformListTile } from '../components/PlatformListTie'; +import { PlatformListTile } from '../components/PlatformListTile'; import { NativeExampleCrashReporting } from '../native/NativeCrashReporting'; export const CrashReportingScreen: React.FC = () => {