android.tsx 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. import {Fragment} from 'react';
  2. import ExternalLink from 'sentry/components/links/externalLink';
  3. import List from 'sentry/components/list/';
  4. import ListItem from 'sentry/components/list/listItem';
  5. import {Layout, LayoutProps} from 'sentry/components/onboarding/gettingStartedDoc/layout';
  6. import {ModuleProps} from 'sentry/components/onboarding/gettingStartedDoc/sdkDocumentation';
  7. import {StepType} from 'sentry/components/onboarding/gettingStartedDoc/step';
  8. import {
  9. PlatformOption,
  10. useUrlPlatformOptions,
  11. } from 'sentry/components/onboarding/platformOptionsControl';
  12. import {ProductSolution} from 'sentry/components/onboarding/productSelection';
  13. import {t, tct} from 'sentry/locale';
  14. export enum InstallationMode {
  15. AUTO = 'auto',
  16. MANUAL = 'manual',
  17. }
  18. type PlaformOptionKey = 'installationMode';
  19. interface StepsParams {
  20. dsn: string;
  21. hasPerformance: boolean;
  22. hasProfiling: boolean;
  23. installationMode?: InstallationMode;
  24. sourcePackageRegistries?: ModuleProps['sourcePackageRegistries'];
  25. }
  26. // Configuration Start
  27. const autoInstallSteps = [
  28. {
  29. type: StepType.INSTALL,
  30. description: (
  31. <p>
  32. {tct(
  33. 'Add Sentry automatically to your app with the [wizardLink:Sentry wizard] (call this inside your project directory).',
  34. {
  35. wizardLink: (
  36. <ExternalLink href="https://docs.sentry.io/platforms/android/#install" />
  37. ),
  38. }
  39. )}
  40. </p>
  41. ),
  42. configurations: [
  43. {
  44. language: 'bash',
  45. code: `brew install getsentry/tools/sentry-wizard && sentry-wizard -i android`,
  46. },
  47. {
  48. description: (
  49. <Fragment>
  50. {t('The Sentry wizard will automatically patch your application:')}
  51. <List symbol="bullet">
  52. <ListItem>
  53. {tct(
  54. "Update your app's [buildGradle:build.gradle] file with the Sentry Gradle plugin and configure it.",
  55. {
  56. buildGradle: <code />,
  57. }
  58. )}
  59. </ListItem>
  60. <ListItem>
  61. {tct(
  62. 'Update your [manifest: AndroidManifest.xml] with the default Sentry configuration',
  63. {
  64. manifest: <code />,
  65. }
  66. )}
  67. </ListItem>
  68. <ListItem>
  69. {tct(
  70. 'Create [sentryProperties: sentry.properties] with an auth token to upload proguard mappings (this file is automatically added to [gitignore: .gitignore])',
  71. {
  72. sentryProperties: <code />,
  73. gitignore: <code />,
  74. }
  75. )}
  76. </ListItem>
  77. <ListItem>
  78. {t(
  79. "Add an example error to your app's Main Activity to verify your Sentry setup"
  80. )}
  81. </ListItem>
  82. </List>
  83. <p>
  84. {tct(
  85. 'Alternatively, you can also [manualSetupLink:set up the SDK manually].',
  86. {
  87. manualSetupLink: (
  88. <ExternalLink href="https://docs.sentry.io/platforms/android/manual-setup/" />
  89. ),
  90. }
  91. )}
  92. </p>
  93. </Fragment>
  94. ),
  95. },
  96. ],
  97. },
  98. ];
  99. export const steps = ({
  100. dsn,
  101. sourcePackageRegistries,
  102. hasPerformance,
  103. hasProfiling,
  104. installationMode,
  105. }: StepsParams): LayoutProps['steps'] =>
  106. installationMode === InstallationMode.AUTO
  107. ? autoInstallSteps
  108. : [
  109. {
  110. type: StepType.INSTALL,
  111. description: (
  112. <p>
  113. {tct(
  114. 'Add the [sagpLink:Sentry Android Gradle plugin] to your [app:app] module:',
  115. {
  116. sagpLink: (
  117. <ExternalLink href="https://docs.sentry.io/platforms/android/configuration/gradle/" />
  118. ),
  119. app: <code />,
  120. }
  121. )}
  122. </p>
  123. ),
  124. configurations: [
  125. {
  126. language: 'groovy',
  127. partialLoading: sourcePackageRegistries?.isLoading,
  128. code: `
  129. plugins {
  130. id "com.android.application" // should be in the same module
  131. id "io.sentry.android.gradle" version "${
  132. sourcePackageRegistries?.isLoading
  133. ? t('\u2026loading')
  134. : sourcePackageRegistries?.data?.['sentry.java.android.gradle-plugin']?.version ??
  135. '3.12.0'
  136. }"
  137. }
  138. `,
  139. },
  140. ],
  141. },
  142. {
  143. type: StepType.CONFIGURE,
  144. description: (
  145. <Fragment>
  146. <p>
  147. {tct(
  148. '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.',
  149. {
  150. manifest: <code />,
  151. provider: <code />,
  152. }
  153. )}
  154. </p>
  155. <p>{t("Here's an example config which should get you started:")}</p>
  156. </Fragment>
  157. ),
  158. configurations: [
  159. {
  160. language: 'xml',
  161. code: `
  162. <application>
  163. <!-- Required: set your sentry.io project identifier (DSN) -->
  164. <meta-data android:name="io.sentry.dsn" android:value="${dsn}" />
  165. <!-- enable automatic breadcrumbs for user interactions (clicks, swipes, scrolls) -->
  166. <meta-data android:name="io.sentry.traces.user-interaction.enable" android:value="true" />
  167. <!-- enable screenshot for crashes -->
  168. <meta-data android:name="io.sentry.attach-screenshot" android:value="true" />
  169. <!-- enable view hierarchy for crashes -->
  170. <meta-data android:name="io.sentry.attach-view-hierarchy" android:value="true" />${
  171. hasPerformance
  172. ? `
  173. <!-- enable the performance API by setting a sample-rate, adjust in production env -->
  174. <meta-data android:name="io.sentry.traces.sample-rate" android:value="1.0" />`
  175. : ''
  176. }${
  177. hasProfiling
  178. ? `
  179. <!-- enable profiling when starting transactions, adjust in production env -->
  180. <meta-data android:name="io.sentry.traces.profiling.sample-rate" android:value="1.0" />`
  181. : ''
  182. }
  183. </application>
  184. `,
  185. },
  186. ],
  187. },
  188. {
  189. type: StepType.VERIFY,
  190. description: (
  191. <p>
  192. {tct(
  193. "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].",
  194. {
  195. mainActivity: <code />,
  196. }
  197. )}
  198. </p>
  199. ),
  200. configurations: [
  201. {
  202. language: 'kotlin',
  203. code: `
  204. val breakWorld = Button(this).apply {
  205. text = "Break the world"
  206. setOnClickListener {
  207. Sentry.captureException(RuntimeException("This app uses Sentry! :)"))
  208. }
  209. }
  210. addContentView(breakWorld, ViewGroup.LayoutParams(
  211. ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT))
  212. `,
  213. },
  214. ],
  215. },
  216. ];
  217. export const nextStepsManual = [
  218. {
  219. id: 'advanced-configuration',
  220. name: t('Advanced Configuration'),
  221. description: t('Customize the SDK initialization behavior.'),
  222. link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
  223. },
  224. {
  225. id: 'proguard-r8',
  226. name: t('ProGuard/R8'),
  227. description: t('Deobfuscate and get readable stacktraces in your Sentry errors.'),
  228. link: 'https://docs.sentry.io/platforms/android/configuration/gradle/#proguardr8--dexguard',
  229. },
  230. {
  231. id: 'jetpack-compose',
  232. name: t('Jetpack Compose'),
  233. description: t('Learn about our first class integration with Jetpack Compose.'),
  234. link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
  235. },
  236. {
  237. id: 'source-context',
  238. name: t('Source Context'),
  239. description: t('See your source code as part of your stacktraces in Sentry.'),
  240. link: 'https://docs.sentry.io/platforms/android/enhance-errors/source-context/',
  241. },
  242. ];
  243. export const nextStepsAuto = [
  244. {
  245. id: 'advanced-configuration',
  246. name: t('Advanced Configuration'),
  247. description: t('Customize the SDK initialization behavior.'),
  248. link: 'https://docs.sentry.io/platforms/android/configuration/manual-init/#manual-initialization',
  249. },
  250. {
  251. id: 'jetpack-compose',
  252. name: t('Jetpack Compose'),
  253. description: t('Learn about our first class integration with Jetpack Compose.'),
  254. link: 'https://docs.sentry.io/platforms/android/configuration/integrations/jetpack-compose/',
  255. },
  256. ];
  257. // Configuration End
  258. export function GettingStartedWithAndroid({
  259. dsn,
  260. sourcePackageRegistries,
  261. activeProductSelection = [],
  262. ...props
  263. }: ModuleProps) {
  264. const platformOptions: Record<PlaformOptionKey, PlatformOption> = {
  265. installationMode: {
  266. label: t('Installation Mode'),
  267. items: [
  268. {
  269. label: t('Auto'),
  270. value: InstallationMode.AUTO,
  271. },
  272. {
  273. label: t('Manual'),
  274. value: InstallationMode.MANUAL,
  275. },
  276. ],
  277. defaultValue:
  278. navigator.userAgent.indexOf('Win') !== -1
  279. ? InstallationMode.MANUAL
  280. : InstallationMode.AUTO,
  281. },
  282. };
  283. const optionValues = useUrlPlatformOptions(platformOptions);
  284. const installationMode = optionValues.installationMode as InstallationMode;
  285. const hasPerformance = activeProductSelection.includes(
  286. ProductSolution.PERFORMANCE_MONITORING
  287. );
  288. const hasProfiling = activeProductSelection.includes(ProductSolution.PROFILING);
  289. return (
  290. <Layout
  291. steps={steps({
  292. dsn,
  293. sourcePackageRegistries,
  294. hasPerformance,
  295. hasProfiling,
  296. installationMode,
  297. })}
  298. platformOptions={platformOptions}
  299. nextSteps={
  300. installationMode === InstallationMode.AUTO ? nextStepsAuto : nextStepsManual
  301. }
  302. {...props}
  303. />
  304. );
  305. }
  306. export default GettingStartedWithAndroid;