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 { BasePlatformOptions, Docs, DocsParams, OnboardingConfig, } from 'sentry/components/onboarding/gettingStartedDoc/types'; 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 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 [sentryProperties: sentry.properties] with an auth token to upload proguard mappings (this file is automatically added to [gitignore: .gitignore])', { sentryProperties: , gitignore: , } )} {t( "Add an example error to your app's Main Activity to verify your Sentry setup" )}

{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 [manifest: AndroidManifest.xml]. Under the hood Sentry uses a [provider: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.', { manifest: , provider: , } )}

{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 docs: Docs = { onboarding, platformOptions, }; export default docs;