import {Fragment} from 'react'; import ExternalLink from 'sentry/components/links/externalLink'; import List from 'sentry/components/list/'; import ListItem from 'sentry/components/list/listItem'; import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step'; import type { BasePlatformOptions, Docs, DocsParams, OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; import {MobileBetaBanner} from 'sentry/components/onboarding/gettingStartedDoc/utils'; import {getAndroidMetricsOnboarding} from 'sentry/components/onboarding/gettingStartedDoc/utils/metricsOnboarding'; import { getReplayMobileConfigureDescription, getReplayVerifyStep, } from 'sentry/components/onboarding/gettingStartedDoc/utils/replayOnboarding'; import {feedbackOnboardingCrashApiJava} from 'sentry/gettingStartedDocs/java/java'; import {t, tct} from 'sentry/locale'; import {getPackageVersion} from 'sentry/utils/gettingStartedDocs/getPackageVersion'; export enum InstallationMode { AUTO = 'auto', MANUAL = 'manual', } const platformOptions = { installationMode: { label: t('Installation Mode'), items: [ { label: t('Auto'), value: InstallationMode.AUTO, }, { label: t('Manual'), value: InstallationMode.MANUAL, }, ], defaultValue: navigator.userAgent.indexOf('Win') !== -1 ? InstallationMode.MANUAL : InstallationMode.AUTO, }, } satisfies BasePlatformOptions; type PlatformOptions = typeof platformOptions; type Params = DocsParams; const isAutoInstall = (params: Params) => params.platformOptions.installationMode === InstallationMode.AUTO; const getManualInstallSnippet = (params: Params) => ` plugins { id "com.android.application" // should be in the same module id "io.sentry.android.gradle" version "${getPackageVersion( params, 'sentry.java.android.gradle-plugin', '3.12.0' )}" }`; const getConfigurationSnippet = (params: Params) => ` ${ params.isPerformanceSelected ? ` ` : '' }${ params.isProfilingSelected ? ` ` : '' } `; const getVerifySnippet = () => ` val breakWorld = Button(this).apply { text = "Break the world" setOnClickListener { Sentry.captureException(RuntimeException("This app uses Sentry! :)")) } } addContentView(breakWorld, ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))`; const getReplaySetupSnippetKotlin = (params: Params) => ` SentryAndroid.init(context) { options -> options.dsn = "${params.dsn.public}" options.isDebug = true // Currently under experimental options: options.experimental.sessionReplay.onErrorSampleRate = 1.0 options.experimental.sessionReplay.sessionSampleRate = 1.0 }`; const getReplaySetupSnippetXml = () => ` `; const getReplayConfigurationSnippet = () => ` options.experimental.sessionReplay.redactAllText = true options.experimental.sessionReplay.redactAllImages = true`; const onboarding: OnboardingConfig = { install: params => isAutoInstall(params) ? [ { type: StepType.INSTALL, description: tct( 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).', { wizardLink: ( ), } ), configurations: [ { language: 'bash', code: `brew install getsentry/tools/sentry-wizard && sentry-wizard -i android`, }, { description: (

{t('The Sentry wizard will automatically patch your application:')}

{tct( "Update your app's [buildGradle:build.gradle] file with the Sentry Gradle plugin and configure it.", { buildGradle: , } )} {tct( 'Update your [manifest: AndroidManifest.xml] with the default Sentry configuration', { manifest: , } )} {tct( 'Create [code: sentry.properties] with an auth token to upload proguard mappings (this file is automatically added to [code: .gitignore])', { code: , } )} {t( "Add an example error to your app's Main Activity to verify your Sentry setup" )}
), additionalInfo: tct( 'Alternatively, you can also [manualSetupLink:set up the SDK manually].', { manualSetupLink: ( ), } ), }, ], }, ] : [ { type: StepType.INSTALL, description: tct( 'Add the [sagpLink:Sentry Android Gradle plugin] to your [app:app] module:', { sagpLink: ( ), app: , } ), configurations: [ { language: 'groovy', partialLoading: params.sourcePackageRegistries?.isLoading, code: getManualInstallSnippet(params), }, ], }, ], configure: params => isAutoInstall(params) ? [] : [ { type: StepType.CONFIGURE, description: (

{tct( 'Configuration is done via the application [code: AndroidManifest.xml]. Under the hood Sentry uses a [code:ContentProvider] to initialize the SDK based on the values provided below. This way the SDK can capture important crashes and metrics right from the app start.', { code: , } )}

{t("Here's an example config which should get you started:")}

), configurations: [ { language: 'xml', code: getConfigurationSnippet(params), }, ], }, ], verify: params => isAutoInstall(params) ? [] : [ { type: StepType.VERIFY, description: tct( "This snippet contains an intentional error and can be used as a test to make sure that everything's working as expected. You can add it to your app's [mainActivity: MainActivity].", { mainActivity: , } ), configurations: [ { language: 'kotlin', code: getVerifySnippet(), }, ], }, ], nextSteps: params => isAutoInstall(params) ? [ { id: 'advanced-configuration', name: t('Advanced Configuration'), description: t('Customize the SDK initialization behavior.'), link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization', }, { id: 'jetpack-compose', name: t('Jetpack Compose'), description: t( 'Learn about our first class integration with Jetpack Compose.' ), link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/', }, ] : [ { id: 'advanced-configuration', name: t('Advanced Configuration'), description: t('Customize the SDK initialization behavior.'), link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization', }, { id: 'proguard-r8', name: t('ProGuard/R8'), description: t( 'Deobfuscate and get readable stacktraces in your Sentry errors.' ), link: 'https://docs.sentry.io/platforms/android/configuration/gradle/#proguardr8--dexguard', }, { id: 'jetpack-compose', name: t('Jetpack Compose'), description: t( 'Learn about our first class integration with Jetpack Compose.' ), link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/', }, { id: 'source-context', name: t('Source Context'), description: t('See your source code as part of your stacktraces in Sentry.'), link: 'https://docs.sentry.io/platforms/android/enhance-errors/source-context/', }, ], }; const replayOnboarding: OnboardingConfig = { introduction: () => ( ), install: (params: Params) => [ { type: StepType.INSTALL, description: tct( "Make sure your Sentry Android SDK version is at least 7.12.0. The easiest way to update through the Sentry Android Gradle plugin to your app module's [code:build.gradle] file.", {code: } ), configurations: [ { code: [ { label: 'Groovy', value: 'groovy', language: 'groovy', filename: 'app/build.gradle', code: `plugins { id "com.android.application" id "io.sentry.android.gradle" version "${getPackageVersion( params, 'sentry.java.android.gradle-plugin', '4.11.0' )}" }`, }, { label: 'Kotlin', value: 'kotlin', language: 'kotlin', filename: 'app/build.gradle.kts', code: `plugins { id("com.android.application") id("io.sentry.android.gradle") version "${getPackageVersion( params, 'sentry.java.android.gradle-plugin', '4.11.0' )}" }`, }, ], }, { description: tct( 'If you have the SDK installed without the Sentry Gradle Plugin, you can update the version directly in the [code:build.gradle] through:', {code: } ), }, { code: [ { label: 'Groovy', value: 'groovy', language: 'groovy', filename: 'app/build.gradle', code: `dependencies { implementation 'io.sentry:sentry-android:${getPackageVersion( params, 'sentry.java.android', '7.14.0' )}' }`, }, { label: 'Kotlin', value: 'kotlin', language: 'kotlin', filename: 'app/build.gradle.kts', code: `dependencies { implementation("io.sentry:sentry-android:${getPackageVersion( params, 'sentry.java.android', '7.14.0' )}") }`, }, ], }, { description: t( 'To set up the integration, add the following to your Sentry initialization:' ), }, { code: [ { label: 'Kotlin', value: 'kotlin', language: 'kotlin', code: getReplaySetupSnippetKotlin(params), }, { label: 'XML', value: 'xml', language: 'xml', filename: 'AndroidManifest.xml', code: getReplaySetupSnippetXml(), }, ], }, ], }, ], configure: () => [ { type: StepType.CONFIGURE, description: getReplayMobileConfigureDescription({ link: 'https://docs.sentry.io/platforms/android/session-replay/#privacy', }), configurations: [ { description: t( 'The following code is the default configuration, which masks and blocks everything.' ), code: [ { label: 'Kotlin', value: 'kotlin', language: 'kotlin', code: getReplayConfigurationSnippet(), }, ], }, ], }, ], verify: getReplayVerifyStep({ replayOnErrorSampleRateName: 'options\u200b.experimental\u200b.sessionReplay\u200b.onErrorSampleRate', replaySessionSampleRateName: 'options\u200b.experimental\u200b.sessionReplay\u200b.sessionSampleRate', }), nextSteps: () => [], }; const docs: Docs = { onboarding, feedbackOnboardingCrashApi: feedbackOnboardingCrashApiJava, crashReportOnboarding: feedbackOnboardingCrashApiJava, customMetricsOnboarding: getAndroidMetricsOnboarding(), platformOptions, replayOnboarding, }; export default docs;