diff --git a/ec.config.mjs b/ec.config.mjs index 7b0075176..573e0a392 100644 --- a/ec.config.mjs +++ b/ec.config.mjs @@ -1,12 +1,14 @@ -import { defineEcConfig } from 'astro-expressive-code' +import { defineEcConfig } from 'astro-expressive-code'; import { pluginCollapsibleSections } from "@expressive-code/plugin-collapsible-sections"; +import { pluginLineNumbers } from "@expressive-code/plugin-line-numbers"; export default defineEcConfig({ defaultProps: { - wrap: true + wrap: true, + showLineNumbers: true, }, // This is where you can pass your plugin options - plugins: [pluginCollapsibleSections()], + plugins: [pluginCollapsibleSections(), pluginLineNumbers()], frames: { extractFileNameFromCode: true }, diff --git a/markdoc.config.mjs b/markdoc.config.mjs index d5fc53a86..89acd1316 100644 --- a/markdoc.config.mjs +++ b/markdoc.config.mjs @@ -77,6 +77,15 @@ export default defineMarkdocConfig({ type: Boolean, required: false, default: false + }, + showLineNumbers: { + type: Boolean, + required: false, + default: true, + }, + startLineNumber: { + type: Number, + required: false, } } }, @@ -133,5 +142,19 @@ export default defineMarkdocConfig({ tabs: { render: component("src/components/Tabs.astro"), }, + exampleapp: { + render: component("src/components/ExampleApp.astro"), + attributes: { + permalink: { + type: String, + required: true, + }, + lang: { + type: String, + required: false, + default: "txt", + } + } + } } }) diff --git a/package-lock.json b/package-lock.json index e108c6d2a..3bebd39aa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "@astrojs/sitemap": "^3.2.1", "@astrojs/tailwind": "^5.1.2", "@expressive-code/plugin-collapsible-sections": "^0.35.6", + "@expressive-code/plugin-line-numbers": "^0.38.3", "@nanostores/persistent": "^0.10.2", "@nanostores/react": "^0.8.0", "@octokit/core": "^6.1.2", @@ -1586,6 +1587,32 @@ "@expressive-code/core": "^0.35.6" } }, + "node_modules/@expressive-code/plugin-line-numbers": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/@expressive-code/plugin-line-numbers/-/plugin-line-numbers-0.38.3.tgz", + "integrity": "sha512-QbK9NL44ST9w5ANVEu0a7fkjlq+fXgxyPqiSyFC4Nw/sAXd0MUwT1C8V0qlve4pZYLz53CR9tn4JQQbR0Z1tOg==", + "license": "MIT", + "dependencies": { + "@expressive-code/core": "^0.38.3" + } + }, + "node_modules/@expressive-code/plugin-line-numbers/node_modules/@expressive-code/core": { + "version": "0.38.3", + "resolved": "https://registry.npmjs.org/@expressive-code/core/-/core-0.38.3.tgz", + "integrity": "sha512-s0/OtdRpBONwcn23O8nVwDNQqpBGKscysejkeBkwlIeHRLZWgiTVrusT5Idrdz1d8cW5wRk9iGsAIQmwDPXgJg==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.0.4", + "hast-util-select": "^6.0.2", + "hast-util-to-html": "^9.0.1", + "hast-util-to-text": "^4.0.1", + "hastscript": "^9.0.0", + "postcss": "^8.4.38", + "postcss-nested": "^6.0.1", + "unist-util-visit": "^5.0.0", + "unist-util-visit-parents": "^6.0.1" + } + }, "node_modules/@expressive-code/plugin-shiki": { "version": "0.35.6", "resolved": "https://registry.npmjs.org/@expressive-code/plugin-shiki/-/plugin-shiki-0.35.6.tgz", diff --git a/package.json b/package.json index 94aee7d96..cdfec5a36 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "@astrojs/sitemap": "^3.2.1", "@astrojs/tailwind": "^5.1.2", "@expressive-code/plugin-collapsible-sections": "^0.35.6", + "@expressive-code/plugin-line-numbers": "^0.38.3", "@nanostores/persistent": "^0.10.2", "@nanostores/react": "^0.8.0", "@octokit/core": "^6.1.2", diff --git a/src/components/CodeBlock.astro b/src/components/CodeBlock.astro index e4c48c3ce..0670137aa 100644 --- a/src/components/CodeBlock.astro +++ b/src/components/CodeBlock.astro @@ -10,6 +10,8 @@ interface Props { ins?: string; del?: string; useDiffSyntax?: boolean; + showLineNumbers?: boolean; + startLineNumber: Number; } const { @@ -19,64 +21,47 @@ const { del, collapse, useDiffSyntax = false, + showLineNumbers = false, + startLineNumber = undefined, } = Astro.props as Props; -let content = ""; - -if (Astro.slots.has("default")) { - // Get the raw content of the slot without transformations - content = await Astro.slots.render("default"); -} - -const parseHighlight = ( - highlight: string, -): MarkerDefinition | MarkerDefinition[] => { +const parseHighlight = (highlight: string): MarkerDefinition[] => { return highlight.split(",").map((item) => { const trimmedItem = item.trim(); - - if (trimmedItem.startsWith("{") && trimmedItem.endsWith("}")) { + if (/^\{.*\}$/.test(trimmedItem)) { const innerContent = trimmedItem.slice(1, -1).trim(); - - // Check if the inner content contains a colon if (innerContent.includes(":")) { const [key, value] = innerContent.split(":").map((part) => part.trim()); - return { [key]: value.replace(/"/g, "") } as MarkerDefinition; + return { [key]: value.replace(/['"]/g, "") } as MarkerDefinition; } - - // If no colon, treat it as a regular string token - return trimmedItem; - } - - if (trimmedItem.startsWith("/") && trimmedItem.endsWith("/")) { + } else if (/^\/.*\/$/.test(trimmedItem)) { return new RegExp(trimmedItem.slice(1, -1), "g") as MarkerDefinition; } - - return trimmedItem.replace(/'/g, ""); + return trimmedItem.replace(/['"]/g, "") as MarkerDefinition; }) as MarkerDefinition[]; }; -const parseCollapse = (collapse?: string | string[]): string[] => { - if (typeof collapse === "string") { - return collapse.split(",").map((item) => item.trim()); - } +const parseCollapse = (collapse?: string | string[]): string[] => + typeof collapse === "string" + ? collapse.split(",").map((item) => item.trim()) + : collapse || []; - return Array.isArray(collapse) ? collapse : []; -}; +const { code, lang } = await extractCodeFromHTML( + await Astro.slots.render("default"), +); -const { code, lang } = await extractCodeFromHTML(content); -const parsedHighlight = highlight ? parseHighlight(highlight) : undefined; -const parsedIns = ins ? parseHighlight(ins) : undefined; -const parsedDel = del ? parseHighlight(del) : undefined; -const parsedCollapse = collapse ? parseCollapse(collapse) : undefined; +const codeAttributes = { + title, + lang, + code, + collapse: collapse ? parseCollapse(collapse) : [], + mark: highlight ? parseHighlight(highlight) : [], + ins: ins ? parseHighlight(ins) : [], + del: del ? parseHighlight(del) : [], + useDiffSyntax, + showLineNumbers, + ...(startLineNumber && { startLineNumber }), +}; --- - + diff --git a/src/components/DefList.astro b/src/components/DefList.astro index e9625e109..2d41290ea 100644 --- a/src/components/DefList.astro +++ b/src/components/DefList.astro @@ -1,7 +1,6 @@ --- -import { decode } from "tiny-decode"; import { parseDefList } from "@components/utils/parseDefList"; -const content = decode(await Astro.slots.render("default")); +const content = await Astro.slots.render("default"); const parsedContent = await parseDefList(content); --- diff --git a/src/components/ExampleApp.astro b/src/components/ExampleApp.astro new file mode 100644 index 000000000..d18f2dc6c --- /dev/null +++ b/src/components/ExampleApp.astro @@ -0,0 +1,19 @@ +--- +import { fetchExampleApp } from "@components/utils/fetchExampleApp"; +import { Code as ExpressiveCode } from "astro-expressive-code/components"; + +interface Props { + permalink: string; + lang: string; +} + +const { permalink, lang } = Astro.props as Props; +const { code, title } = await fetchExampleApp(permalink); +const codeAttributes = { + code, + lang, + title, +}; +--- + + diff --git a/src/components/utils/extractCode.ts b/src/components/utils/extractCode.ts index 8b6452dba..6ed71a0eb 100644 --- a/src/components/utils/extractCode.ts +++ b/src/components/utils/extractCode.ts @@ -1,6 +1,6 @@ import { unified } from "unified"; import rehypeParse from "rehype-parse"; -import { selectAll, select } from "hast-util-select"; +import { select, selectAll } from "hast-util-select"; import { toString } from "hast-util-to-string"; interface CodeExtractionResult { @@ -8,12 +8,16 @@ interface CodeExtractionResult { lang?: string; } -export const extractCodeFromHTML = async (htmlString: string): Promise => { +export const extractCodeFromHTML = async ( + htmlString: string, +): Promise => { const processor = unified().use(rehypeParse, { fragment: true }); const ast = processor.parse(htmlString); const preElement = select("pre[data-language]", ast); - const lang = preElement ? preElement.properties["dataLanguage"] as string : ""; + const lang = preElement + ? preElement.properties["dataLanguage"] as string + : ""; const codeBlocks = selectAll(".ec-line .code", ast); diff --git a/src/components/utils/fetchExampleApp.ts b/src/components/utils/fetchExampleApp.ts new file mode 100644 index 000000000..2ea80205d --- /dev/null +++ b/src/components/utils/fetchExampleApp.ts @@ -0,0 +1,67 @@ +import { Octokit } from "@octokit/core"; + +const octokit = new Octokit({ auth: import.meta.env.VITE_GITHUB_TOKEN }); + +/** + * Parses a file URL and returns its component parts + * @param fileUrl + * @returns The component parts of the URL for use in a GraphQL query + */ +function parsePermalink(fileUrl: string) { + const regex = + /https:\/\/github\.com\/([^\/]+)\/([^\/]+)\/blob\/([^\/]+)\/(.+)/; + const match = fileUrl.match(regex); + if (!match) { + throw new Error("Invalid file URL format."); + } + + const [, owner, repo, branch, filePath] = match; + + const filename = filePath.split("/").pop()!; + + return { owner, repo, branch, filePath, filename }; +} + +/** + * Fetches the text content of a file from GitHub + * @param fileUrl + * @returns The file name and contents + */ +export async function fetchExampleApp( + fileUrl: string, +): Promise<{ code: string; title: string }> { + const { owner, repo, branch, filePath, filename } = parsePermalink(fileUrl); + + const query = ` + query($owner: String!, $repo: String!, $expression: String!) { + repository(owner: $owner, name: $repo) { + object(expression: $expression) { + ... on Blob { + text + } + } + } + } + `; + + const expression = `${branch}:${filePath}`; + + const variables = { owner, repo, expression }; + + try { + const response = await octokit.graphql< + { repository: { object: { text: string } } } + >(query, variables); + + if (!response.repository.object) { + throw new Error("File not found in the repository."); + } + + const { text: code } = response.repository.object; + return { code, title: filename }; + } catch (error) { + throw new Error( + `Failed to fetch file content: ${(error as Error).message}`, + ); + } +} diff --git a/src/content/docs/en/sdk/adobe-extension/android/attribution.mdoc b/src/content/docs/en/sdk/adobe-extension/android/attribution.mdoc new file mode 100644 index 000000000..7eab55016 --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/attribution.mdoc @@ -0,0 +1,133 @@ +--- +title: Set up an attribution callback +description: Set up an attribution callback to respond to attribution changes. +sidebar-position: 2 +--- + +When Adjust receives install data from the Adjust Android Extension for Adobe Experience SDK, the device is attributed to the source of the install. This attribution information can change if the user is retargeted or interacts with another campaign. + +You can configure a callback function to respond to attribution changes. When Adjust receives new attribution information, it sends the data asynchronously back to the device. The callback function receives the device's attribution data as an argument. + +Read Adjust's [attribution data policies](https://github.com/adjust/sdks/blob/master/doc/attribution-data.md) for more information about attribution data. + +## Reference {% #reference %} + +To set a callback function to listen for attribution changes, call the `setOnAttributionChangedListener` method of your `AdjustAdobeExtensionConfig` instance with the following argument: + +{% deflist %} +`onAttributionChangedListener`: `OnAttributionChangedListener` + +: A function that returns `void` and receives device attribution information as a serialized JSON object. +{% /deflist %} + +## Tutorial: Create an attribution callback {% #tutorial %} + +To configure an attribution callback, you need to create a function and assign it to your `AdjustAdobeExtensionConfig` instance. In this tutorial, you'll build on `MainApp.java` from the [integration guide](/en/sdk/adobe-extension/android/integration) and add an `onAttributionChanged` callback function that outputs the user's attribution information to logs as a string. The final result looks like this: + +```java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; + +public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution adjustAttribution) { + Log.d("example", "Attribution information updated"); + Log.d("example", "Attribution: " + attribution.toString()); + } + }); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } +} +``` + +Here's what you need to do: + +1. Inside the `try...catch` block, call the `setOnAttributionChangedListener` method of your `AdjustAdobeExtensionConfig` instance. Pass an `OnAttributionChangedListener` instance as an argument. + + {% codeblock highlight="{range: 6}" startLineNumber=21 %} + ```java + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setOnAttributionChangedListener(new OnAttributionChangedListener() {}); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + ``` + {% /codeblock %} + +1. Create a new public function called `onAttributionChanged` inside your `setOnAttributionChangedListener` declaration. This method takes an `AdjustAttribution` argument and returns `void`. + + {% codeblock + title="MainApp.java" + highlight="{range: 3}" + startLineNumber=26 %} + ```java + config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution adjustAttribution) {} + }); + ``` + {% /codeblock %} + +1. Inside the `onAttributionChanged` function body, log the `AdjustAttribution` object by converting it to a string. + + {% codeblock + title="MainApp.java" + highlight="{range: 4-5}" + startLineNumber=26 %} + ```java + config.setOnAttributionChangedListener(new OnAttributionChangedListener() { + @Override + public void onAttributionChanged(AdjustAttribution adjustAttribution) { + Log.d("example", "Attribution information updated"); + Log.d("example", "Attribution: " + attribution.toString()); + } + }); + ``` + {% /codeblock %} + +That's it! When a user's attribution information changes, this callback function writes out the updated attribution information to the system log. diff --git a/src/content/docs/en/sdk/adobe-extension/android/deep-linking.mdoc b/src/content/docs/en/sdk/adobe-extension/android/deep-linking.mdoc new file mode 100644 index 000000000..5a651093f --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/deep-linking.mdoc @@ -0,0 +1,196 @@ +--- +title: Set up deep linking +description: Configure your app to handle direct and deferred deep links. +sidebar-position: 6 +--- + +Deep links are URIs (Uniform Resource Identifiers) that direct users to specific pages within your app. They enhance user experience by guiding them directly to relevant content after they interact with a link. + +The Adjust Android Extension for the Adobe Experience SDK supports two types of deep linking, based on whether the user has already installed your app: + +- **Direct deep links**: If the user already has your app installed, the link opens the specified page. +- **Deferred deep links**: If the user doesn’t have your app installed, the link directs them to the app store to install it. After installation, the app opens the specified page. + +## Reattribute users with direct deep links {% #reattribute-users-with-direct-deep-links %} + +You can reattribute your users by sending deep link information to Adjust. When a user engages with a deep link, you can send this data to Adjust to update their attribution information. + +1. First, create an `AdjustDeeplink` instance with your deep link URI. The `AdjustDeeplink` class validates this URI and checks the formatted string to ensure successful processing. + +1. Then, call the `Adjust.processDeeplink` function to handle the deep link and pass the information to Adjust. + +The `AdjustDeeplink` class constructor requires the following argument: + +{% deflist %} +`url`: `Uri` + +: The deep link URI that opens your app. +{% /deflist %} + +The `Adjust.processDeeplink` function requires the following arguments: + +{% deflist %} +`adjustDeeplink`: `AdjustDeeplink` + +: The `AdjustDeeplink` instance you created. + +`context`: `Context` + +: The application context. +{% /deflist %} + +## Deferred deep link callbacks {% #deferred-deep-link-callbacks %} + +The Adjust Android Extension for Adobe Experience SDK opens deferred deep links by default. To control this behavior, or perform validation before the deep link is opened, configure the extension to call a function when the app opens via a deferred deep link. + +1. Call `setOnDeferredDeeplinkResponseListener` on your `AdjustAdobeExtensionConfig` instance. +1. Call `AdjustAdobeExtension.setConfiguration` to set your configuration. + +The `OnDeferredDeeplinkResponseListener` function requires the following argument: + +{% deflist %} +`onDeferredDeeplinkResponseListener`: `OnDeferredDeeplinkResponseListener` + +: A function that returns a `boolean` value. If it returns `false`, the extension won't open the deferred deep link. +{% /deflist %} + +### Tutorial: Create a deferred deep link function {% #tutorial %} + +If you followed the [integration guide](/en/sdk/adobe-extension/android/integration), you've already configured the Adjust Extension to process and open deep links. If you haven't done this, refer to [set up deep link handling](/en/sdk/adobe-extension/android/integration#set-up-deep-link-handling) for instructions. + +In this tutorial, you'll learn how to create a callback function that controls deep linking functionality using the `setOnDeferredDeeplinkResponseListener` method. The function will open the link depending on the following condition: + +"If the deep link contains `"no_open"`, the app won't open it." + +The result looks like this: + +```java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; + +public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (deeplink.contains("no_open")) { + return false; + } else { + return true; + } + } + }); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } +} +``` + +Here's what you need to do: + +1. Inside the `try...catch` block, call the `setOnDeferredDeeplinkResponseListener` method of your `AdjustAdobeExtensionConfig` instance. Pass an `OnDeferredDeeplinkResponseListener` instance as an argument. + + {% codeblock + title="MainApp.java" + highlight="{range: 6}" + startLineNumber=21 %} + ```java + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() {}); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + ``` + {% /codeblock %} + +1. Create a new public function called `launchReceivedDeeplink` inside your `OnDeferredDeeplinkResponseListener` declaration. This method takes a `Uri` argument and returns a `boolean`. + + {% codeblock + title="MainApp.java" + highlight="{range: 3}" + startLineNumber=26 %} + ```java + config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) {} + }); + ``` + {% /codeblock %} + +1. Add an `if` condition to the `launchReceivedDeeplink` to check if the `deeplink` contains the value `"no_open"`. If the string is found, the function returns `false`, and the app shouldn't open the deferred deep link. + + {% codeblock + title="MainApp.java" + highlight="{range: 3-5}" + startLineNumber=27 %} + ```java + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (deeplink.contains("no_open")) { + return false; + } + } + ``` + {% /codeblock %} + +1. Finally, add an `else` block to return `true` if the deep link doesn't contain `"no_open"`. + + {% codeblock + title="MainApp.java" + highlight="{range: 5-7}" + startLineNumber=27 %} + ```java + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (deeplink.contains("no_open")) { + return false; + } else { + return true; + } + } + ``` + {% /codeblock %} + +That's it! When a user opens your app with a deferred deep link, the Adjust Extension will check if the link contains the string `"no_open"`. If it does, the app won't open the deep link. diff --git a/src/content/docs/en/sdk/adobe-extension/android/events.mdoc b/src/content/docs/en/sdk/adobe-extension/android/events.mdoc new file mode 100644 index 000000000..2ec90fc5c --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/events.mdoc @@ -0,0 +1,259 @@ +--- +title: Send event information +description: Follow this guide to send events to Adjust from your Adobe Experience app. +sidebar-position: 5 +--- + +You can use the Adjust Extension for Adobe Experience SDK to send event information to Adjust's servers when your users take specific actions. Adjust records these events and surfaces them in your [Datascape reports](https://help.adjust.com/en/article/datascape), [server callbacks](https://help.adjust.com/en/article/server-callbacks), and [cloud storage uploads](https://help.adjust.com/en/article/cloud-storage-uploads). + +For more information on configuring events in Adjust, visit the [Add events guide](https://help.adjust.com/en/article/add-events) in the Help Center. + +## How it works {% #how-it-works %} + +Event information is sent to Adjust when the following information is passed to the `MobileCore.trackAction` API: + +1. `AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT`: a string value that maps to the Adjust `trackEvent` method. +1. `contextData`: a HashMap of values used to configure your event. + +When you call `MobileCore.trackAction` with these arguments, the Adjust extension creates an event instance, passes it to the `trackEvent` method, and sends the information to Adjust. + +## Reference {% #reference %} + +The `contextData` HashMap holds information about an event. Each event is represented by a unique `contextData` HashMap. To configure your event instance, add values to HashMap. + +The following keys are supported: + +{% deflist %} +`AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN` + +: Your Adjust event token. You MUST set this value to send event information to Adjust. Check out [add events](https://help.adjust.com/en/article/add-events#manage-your-events) for more information. + +`AdjustAdobeExtension.ADOBE_ADJUST_REVENUE` + +: The amount of revenue associated with the event. This value should be a string that represents a numerical value. + +`AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY`. + +: An [ISO 4217](https://www.iban.com/currency-codes) currency code. + +`AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX` + +: Append a callback parameter key to this prefix and add your callback parameter value to send callbacks to Adjust. + +`AdjustAdobeExtension.ADOBE_ADJUST_EVENT_PARTNER_PARAM_PREFIX` + +: Append a partner parameter key to this prefix and add your partner parameter value to send callbacks to third parties. +{% /deflist %} + +## Tutorial: Send an event {% #tutorial %} + +To send event information, you need to add a function to your main activity. In this tutorial, you'll build on `MainActivity.java` from the [integration guide](/en/sdk/adobe-extension/android/integration) and add a new function called `sendEventToAdjust` which will send an event with the following properties: + +- An event token: `"g3mfiw"`. +- 1 Euro of event revenue. +- A callback parameter with the key `"user_id"` and value `"855"`. +- A partner parameter with the key `"event_token` and value `"g3mfiw"`. + +The final result looks like this: + +```java +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; +import com.adobe.marketing.mobile.MobileCore; + +import java.util.HashMap; +import java.util.Map; + +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_REVENUE, "1.00"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY, "EUR"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX + "user_id", "855"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_PARTNER_PARAM_PREFIX + "event_token", "g3mfiw"); + + MobileCore.trackAction(action, contextData); + } +} +``` + +Here's what you need to do: + +1. First, import the following classes: + + - `com.adobe.marketing.mobile.MobileCore`: this class is used to send information to Adobe and Adjust. + - `java.util.HashMap`: this class is used to generate the `contextData` HashMap. + - `java.util.Map`: this class is used to type the `contextData` HashMap. + + ```java + // MainActivity.java + import com.adobe.marketing.mobile.MobileCore; + + import java.util.HashMap; + import java.util.Map; + ``` + +1. Next, create a new function inside the `MainActivity` class called `sendEventToAdjust`. This function takes [the application `View`](https://developer.android.com/reference/android/view/View) as an argument and returns `void.` + + {% codeblock + title="MainActivity.java" + highlight="{range: 13}" + startLineNumber=15 %} + ```java + public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + + public void sendEventToAdjust(View view) {} + } + ``` + {% /codeblock %} + +1. Inside the `sendEventToAdjust` function, declare a new `String` variable called `action` and assign it the value `AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT`. This is used to tell `MobileCore.trackAction` which action to handle. + + {% codeblock + title="MainActivity.java" + highlight="{range: 2}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + } + ``` + {% /codeblock %} + +1. Create a new HashMap variable called `contextData`. This is used to hold the properties of the event. + + {% codeblock + title="MainActivity.java" + highlight="{range: 3}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + } + ``` + {% /codeblock %} + +Now that the `contextData` HashMap is initialized, add values to build the event. You can refer back to the [`contextData` reference](#reference) for more information about the uses of each key. + +1. Add your Adjust event token to the HashMap using the `AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN` key. This is required to inform Adjust which event you're trying to send. + + {% codeblock + title="MainActivity.java" + highlight="{range: 4}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + } + ``` + {% /codeblock %} + +1. Add the event revenue amount using `AdjustAdobeExtension.ADOBE_ADJUST_REVENUE` for the amount and `AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY` for the currency. Both values MUST be passed as strings. + + {% codeblock + title="MainActivity.java" + highlight="{range: 5-6}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_REVENUE, "1.00"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY, "EUR"); + } + ``` + {% /codeblock %} + +1. Add a callback parameter using the `AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX` key. Append a callback identifier to the key to match the parameter in your callback URL. + + {% codeblock + title="MainActivity.java" + highlight="{range: 7}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_REVENUE, "1.00"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY, "EUR"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX + "user_id", "855"); + } + ``` + {% /codeblock %} + +1. Add a partner parameter using the `AdjustAdobeExtension.ADOBE_ADJUST_EVENT_PARTNER_PARAM_PREFIX` key. Append a callback identifier to the key to map it to your partner's placeholder. + + {% codeblock + title="MainActivity.java" + highlight="{range: 8}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_REVENUE, "1.00"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY, "EUR"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX + "user_id", "855"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_PARTNER_PARAM_PREFIX + "event_token", "g3mfiw"); + } + ``` + {% /codeblock %} + +1. Finally, to send the event information to Adjust, call `MobileCore.trackAction` with your `action` and `contextData` variables. + + {% codeblock + title="MainActivity.java" + highlight="{range: 10}" + startLineNumber=27 %} + ```java + public void sendEventToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_TOKEN, "g3mfiw"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_REVENUE, "1.00"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_CURRENCY, "EUR"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_CALLBACK_PARAM_PREFIX + "user_id", "855"); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_EVENT_PARTNER_PARAM_PREFIX + "event_token", "g3mfiw"); + + MobileCore.trackAction(action, contextData); + } + ``` + {% /codeblock %} + +That's it! When the user performs an action that maps to the `sendEventToAdjust` function, an event is constructed and sent to Adjust. diff --git a/src/content/docs/en/sdk/adobe-extension/android/example.mdoc b/src/content/docs/en/sdk/adobe-extension/android/example.mdoc new file mode 100644 index 000000000..c37bdd4b4 --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/example.mdoc @@ -0,0 +1,18 @@ +--- +title: Android Adobe Extension example implementation +description: A full example of an app using all features of the Adjust Extension. +sidebar-label: Example +sidebar-position: 9 +--- + +This page contains a full example implementation of the Adjust Android Extension for Adobe Experience SDK. + +You can see [the full example on GitHub](https://github.com/adjust/android_adobe_extension/tree/main/AdjustAdobeExtension/example-app). + +{% exampleapp + permalink="https://github.com/adjust/android_adobe_extension/blob/main/AdjustAdobeExtension/example-app/src/main/java/com/adjust/examples/MainApp.java" + lang="java" /%} + +{% exampleapp + permalink="https://github.com/adjust/android_adobe_extension/blob/main/AdjustAdobeExtension/example-app/src/main/java/com/adjust/examples/MainActivity.java" + lang="java" /%} diff --git a/src/content/docs/en/sdk/adobe-extension/android/external-device-id.mdoc b/src/content/docs/en/sdk/adobe-extension/android/external-device-id.mdoc new file mode 100644 index 000000000..dc76ab81f --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/external-device-id.mdoc @@ -0,0 +1,97 @@ +--- +title: Configure external device ID +description: Use external device IDs to enhance your reporting. +sidebar-position: 4 +--- + +An [external device identifier](https://help.adjust.com/en/article/external-device-identifiers) is a custom value that you can assign to a device or user. This helps you recognize users across sessions and platforms. External device IDs also help you deduplicate installs by user, to avoid counting multiple new installs assoiciated with the same user. + +Using external device IDs can produce different results depending on your setup. If you want to use them, contact your Adjust representative. They will talk you through the best approach for your use case. + +You must set your external device ID in your `AdjustAdobeExtensionConfig` instance before you call `AdjustAdobeExtension.setConfiguration`. You can't change this property after you've initialized the extension. + +## Reference {% #reference %} + +To set an external device ID, call the `setExternalDeviceId` method of your `AdjustAdobeExtensionConfig` instance with the following argument: + +{% deflist %} +`externalDeviceId`: `String` + +: Your external device identifier. +{% /deflist %} + +## Tutorial: Set an external device ID {% #tutorial %} + +To set an external device ID, you need to set the ID using your `AdjustAdobeExtensionConfig` instance. If you followed the [integration guide](/en/sdk/adobe-extension/android/integration), your `MainApp.java` file should look something like this: + +```java +// MainApp.java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; + +public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } +} +``` + +To set a default link token for preinstalled apps, pass the link token to the `setExternalDeviceId` method of the `AdjustAdobeExtensionConfig` instance. The ID is sent to Adjust with each session. + +In this example, the external device ID is set to _{% $variables.config.externalDeviceId %}_. + +{% codeblock + title="MainApp.java" + highlight="{range: 6}" + startLineNumber=21 %} +```java +try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setExternalDeviceId("{% $variables.config.externalDeviceId %}"); + AdjustAdobeExtension.setConfiguration(config); +} catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); +} +``` +{% /codeblock %} diff --git a/src/content/docs/en/sdk/adobe-extension/android/global-parameters.mdoc b/src/content/docs/en/sdk/adobe-extension/android/global-parameters.mdoc new file mode 100644 index 000000000..9ca2106aa --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/global-parameters.mdoc @@ -0,0 +1,205 @@ +--- +title: Set up global callback and partner parameters +description: Send information to your callback URL and to network partners with each session. +sidebar-label: Set up global parameters +sidebar-position: 7 +--- + +The Adjust Android Extension for Adobe Experience SDK enables you to send additional information to Adjust to forward to your callback URL and network partners. Global parameters are string key-value pairs that you can use to communicate more information about a device or user. + +## Global callback parameters {% #global-callback-parameters %} + +If you [register a callback URL](https://help.adjust.com/en/article/recommended-placeholders-callbacks) in the Adjust dashboard, Adjust sends a `GET` request to your callback URL when the SDK sends session data. To append parameters to this callback request, set the global parameters in your code. + +#### Reference {% #global-callback-parameters-reference %} + +The `Adjust` class methods manage the global callback parameters. You can add and remove individual parameters, or reset all parameters at once. + +### Add a global callback parameter {% #add-global-callback-parameter %} + +To add a global callback parameter, call the `Adjust.addGlobalCallbackParameter` method with the following arguments: + +{% deflist %} +`key`: `String` + +: The parameter key. + +`value`: `String` + +: The parameter value. +{% /deflist %} + +You can add multiple parameters by calling the `Adjust.addGlobalCallbackParameter` method multiple times. + +```java +Adjust.addGlobalCallbackParameter("key", "value"); +Adjust.addGlobalCallbackParameter("user_id", "855"); +``` + +### Remove a global callback parameter {% #remove-global-callback-parameter %} + +To remove a global callback parameter, call the `Adjust.removeGlobalCallbackParameter` method with the following argument: + +{% deflist %} +`key`: `String` + +: The key of the parameter you want to remove. +{% /deflist %} + +```java +Adjust.removeGlobalCallbackParameter("key"); +``` + +### Remove all global callback parameters {% #remove-all-global-callback-parameter %} + +To remove all global callback parameters at once, call the `Adjust.removeGlobalCallbackParameters` method. + +This method removes all active global callback parameters, meaning you won't receive any parameters in callbacks from Adjust. + +```java +Adjust.removeGlobalCallbackParameters(); +``` + +## Global partner parameters {% #global-partner-parameters %} + +You can send extra information to your network partners by adding partner parameters. Sharing additional parameters with your external partners enables more granular analysis and facilitates retargeting. + +When the Adjust Android Extension for Adobe Experience SDK sends session data, Adjust's servers forward any global partner parameters to any partners you've configured. + +Read [choose data sharing options](https://help.adjust.com/en/article/data-sharing-ad-network) to learn how to configure what data you share with external partners. + +#### Reference {% #global-partner-parameters-reference %} + +The `Adjust` class methods manage the global partner parameters. You can add and remove individual parameters, or reset all parameters at once. + +### Add a global partner parameter {% #add-global-partner-parameter %} + +To add a global partner parameter, call the `Adjust.addGlobalPartnerParameter` method with the following arguments: + +{% deflist %} +`key`: `String` + +: The parameter key. + +`value`: `String` + +: The parameter value. +{% /deflist %} + +You can add multiple parameters by calling the `Adjust.addGlobalPartnerParameter` method multiple times. + +```java +Adjust.addGlobalPartnerParameter("key", "value"); +Adjust.addGlobalPartnerParameter("user_id", "855"); +``` + +### Remove a global partner parameter {% #remove-global-partner-parameter %} + +To remove a global partner parameter, call the `Adjust.removeGlobalPartnerParameter` method with the following argument: + +{% deflist %} +`key`: `String` + +: The key of the parameter you want to remove. +{% /deflist %} + +```java +Adjust.removeGlobalPartnerParameter("key"); +``` + +### Remove all global partner parameters {% #remove-all-global-partner-parameter %} + +To remove all global partner parameters at once, call the `Adjust.removeGlobalPartnerParameters` method. + +This method removes all active global partner parameters, meaning no parameters will be sent to network partners. + +```java +Adjust.removeGlobalPartnerParameters(); +``` + +## Tutorial: Add and remove global parameters {% #tutorial %} + +You can change your global callback and partner parameters at any time by calling the methods described on this page. If you followed the [integration guide](/en/sdk/adobe-extension/android/integration), your `MainActivity.java` file should look something like this: + +```java +// MainActivity.java +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; + +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } +} +``` + +Add new functions to update global parameters: + +- `addAdjustGlobalCallback`: This function adds a new global callback. +- `removeAdjustGlobalCallback`: This function removes a global callback added by `addAdjustGlobalCallback`. +- `removeAllAdjustGlobalCallbacks`: This function removes all global callbacks. +- `addAdjustGlobalPartnerParam`: This function adds a new global partner parameter. +- `removeAdjustGlobalPartnerParam`: This function removes the global partner parameter added by `addAdjustGlobalPartnerParam`. +- `removeAllAdjustGlobalPartnerParams`: This function removes all global partner parameter. + +These functions take [a `View`](https://developer.android.com/reference/android/view/View) as an argument and return `void`. To handle the update, call the relevant `Adjust` class method within the body of each function. + +Here's the updated `MainActivity.java` file: + +{% codeblock + title="MainActivity.java" + highlight="{range: 13-35}" + startLineNumber=11 %} +```java +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + + public void addAdjustGlobalCallback(View view) { + Adjust.addGlobalCallbackParameter("user_id", "855"); + } + + public void removeAdjustGlobalCallback(View view) { + Adjust.removeGlobalCallbackParameter("user_id"); + } + + public void removeAllAdjustGlobalCallbacks(View view) { + Adjust.removeGlobalPartnerParameters(); + } + + public void addAdjustGlobalPartnerParam(View view) { + Adjust.addGlobalPartnerParameter("user_id", "855"); + } + + public void removeAdjustGlobalPartnerParam(View view) { + Adjust.removeGlobalPartnerParameter("user_id"); + } + + public void removeAllAdjustGlobalPartnerParams(View view) { + Adjust.removeGlobalPartnerParameters(); + } +} +``` +{% /codeblock %} diff --git a/src/content/docs/en/sdk/adobe-extension/android/index.mdoc b/src/content/docs/en/sdk/adobe-extension/android/index.mdoc new file mode 100644 index 000000000..23523b8bd --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/index.mdoc @@ -0,0 +1,49 @@ +--- +title: Android Adobe Extension integration guide +description: Follow this guide to integrate the Adjust Android Extension for Adobe Experience SDK. +category-title: Android +sidebar-position: 1 +--- + +The Adjust Android Extension for Adobe Experience SDK provides you with a powerful tool to enhance your app's performance analytics. By integrating this extension, you can send essential data—such as install, session, and in-app event information—to Adjust. + +The extension is designed to work within the Adobe Experience SDK framework, so you can implement it without disrupting your existing workflows. + +{% callout type="seealso" %} +The full source code is available [on GitHub](https://github.com/adjust/android_adobe_extension) +{% /callout %} + +## Integrate the extension {% #integrate-the-extension %} + +Follow the [integration guide](/en/sdk/adobe-extension/android/integration) to add the Adjust Android Extension for Adobe Experience SDK to your app. This guide covers the following: + +1. [Install dependencies](/en/sdk/adobe-extension/android/integration#install-the-adjust-extension) +1. [Configure permissions](/en/sdk/adobe-extension/android/integration#configure-permissions) +1. [Integrate the Adjust Android Extension for Adobe Experience SDK](/en/sdk/adobe-extension/android/integration#integration-guide) + +## Set up features {% #set-up-features %} + +The Adjust Android Extension for Adobe Experience SDK has many features that enable you to record user activity. Follow these guides to configure the Adjust Extension: + +- [Set up a callback function to listen for attribution changes](/en/sdk/adobe-extension/android/attribution). +- [Configure a default link token for preinstalled apps](/en/sdk/adobe-extension/android/preinstalled). +- [Configure an external device ID for reporting](/en/sdk/adobe-extension/android/external-device-id). + +Follow these guides to add functionality to your app using the Adjust Extension: + +- [Send event information to Adjust](/en/sdk/adobe-extension/android/events). +- [Set up deep linking](/en/sdk/adobe-extension/android/deep-linking). +- [Set up global callback and partner parameters](/en/sdk/adobe-extension/android/global-parameters). +- [Send push tokens for uninstall measurement](/en/sdk/adobe-extension/android/push-tokens). + +{% callout type="seealso" %} +The [example app](/en/sdk/adobe-extension/android/example) includes an implementation of all features available in the Adjust Android Extension for Adobe Experience SDK. +{% /callout %} + +## Build your app for production {% #build-your-app-for-production %} + +After you've integrated the Adjust Android Extension for Adobe Experience and completed [your testing](/en/sdk/testing), prepare your app for release. Make sure to do the following: + +- [ ] Ask your marketing team to set up all necessary campaigns in Adjust. +- [ ] Set your [logging level](/en/sdk/adobe-extension/android/integration#integration-guide) according to your needs. +- [ ] Change [your environment](/en/sdk/adobe-extension/android/integration#configure-the-adjust-extension) to `AdjustAdobeExtensionConfig.ENVIRONMENT_PRODUCTION` to allow the extension to send data in your production environment. diff --git a/src/content/docs/en/sdk/adobe-extension/android/integration.mdoc b/src/content/docs/en/sdk/adobe-extension/android/integration.mdoc new file mode 100644 index 000000000..9146db226 --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/integration.mdoc @@ -0,0 +1,606 @@ +--- +title: Integration guide +description: Follow this guide to integrate the Adjust Android Extension for Adobe Experience SDK. +sidebar-position: 1 +--- + +This is a step-by-step guide to help you integrate and configure the Adjust Extension in your Adobe Experience app for Android. With this extension, you can seamlessly integrate Adjust with the Adobe Experience SDK to capture and send attribution data and in-app event information. + +This extension enables you to send installs, sessions, custom in-app events, and other types of data to Adjust. Follow this guide to set up and configure the Adjust Extension and verify that you can send install information to Adjust. + +## Set up your project {% #set-up-your-project %} + +Follow these steps to set up your project to support the Adjust Extension for Adobe Experience SDK. + +### Install the Adjust Extension {% #install-the-adjust-extension %} + +To use the Adjust Extension for Adobe Experience SDK, you need to add it to your project as a dependency. The relevant packages are available on [Maven](https://maven.apache.org). + +Add the following to your `build.gradle` file: + +{% deflist %} +`com.adjust.adobeextension:adobeextension` + +: The Adjust extension for Adobe Experience. + +`com.adjust.sdk:adjust-android` + +: The Adjust Android SDK. + +`com.android.installreferrer:installreferrer` + +: The Android Install Referrer API. +{% /deflist %} + +```groovy +dependencies { + implementation 'com.adjust.adobeextension:adobeextension:{% $versions.android_adobe_extension.v3 %}' + implementation 'com.adjust.sdk:adjust-android:{% $versions.android.v5 %}' + implementation 'com.adobe.marketing.mobile:core:3.2.0' + implementation 'com.android.installreferrer:installreferrer:2.2' +} +``` + +### Add Google Play Services {% #add-google-play-services %} + +Apps that target the Google Play Store must use the `gps_adid` (Google Advertising ID) to identify devices. To access the `gps_adid`, add the `play-services-ads-identifier` AAR to your project. + +If you're using Maven, add the `com.google.android.gms:play-services-ads-identifier` implementation to your `build.gradle` file. + +```groovy +dependencies { + implementation 'com.google.android.gms:play-services-ads-identifier:18.0.1' +} +``` + +### Configure permissions {% #configure-permissions %} + +The Adjust Extension for Adobe Experience SDK bundles all required permissions by default. You don't need to add any permissions for the extension to work. + +If your app needs to be COPPA (Children's Online Privacy Protection Act) compliant or you don't target the Google Play Store, you MUST remove the `com.google.android.gms.permission.AD_ID` permission using a `remove` directive in your `AndroidManifest.xml` file. + +```xml + +``` + +{% callout type="seealso" %} +Check the [Apps for children](/en/sdk/apps-for-children) guide for more information about COPPA compliance. +{% /callout %} + +## Integration guide {% #integration-guide %} + +Once you've completed the project setup steps, you can integrate the Adjust SDK. The following guide shows you how to: + +1. Add the Adjust Extension to your Adobe Experience app. +1. Set your logging level to **verbose** to retrieve as much detail as possible from the extension. +1. Test the Extension in **sandbox** mode to ensure it sends data to Adjust. +1. Enable your app to open deep links. +1. Register with the Adobe Experience SDK. + +To do this, you need to create two files: + +- `MainApp.java`: you'll configure and register the Adjust SDK in this file. +- `MainActivity.java`: you'll configure deep link handling in this file. + +### Import classes {% #import-classes %} + +First, you need to import some classes into your application files. Import the following classes into your `MainApp.java` file: + +{% deflist %} +`android.app.Application` + +: Used to create the main application. + +`android.util.Log` + +: Used to output logs. + +`com.adjust.adobeextension.AdjustAdobeExtension` + +: Used to register the Adjust Extension. + +`com.adjust.adobeextension.AdjustAdobeExtensionConfig` + +: Used to configure the Adjust Extension. + +`com.adobe.marketing.mobile.AdobeCallback` + +: Used when registering your extensions. + +`com.adobe.marketing.mobile.Extension` + +: Used to build a list of extensions. + +`com.adobe.marketing.mobile.Analytics` + +: Used to enable analytics in the Adobe Experience SDK. + +`com.adobe.marketing.mobile.Identity` + +: Used to manage user identities in the Adobe Experience SDK + +`com.adobe.marketing.mobile.LoggingMode` + +: Used to configure logging in the Adobe Experience SDK. + +`com.adobe.marketing.mobile.MobileCore` + +: Used to communicate with the Adobe Experience SDK. +{% /deflist %} + +```java +// MainApp.java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; +``` + +Import the following classes into your `MainActivity.java` file: + +{% deflist %} +`android.content.Intent` + +: Used to get the [operation intent from Android](https://developer.android.com/reference/android/content/Intent). + +`android.net.Uri` + +: Used to type deep links. + +`android.os.Bundle` + +: Used to type the app's saved instance state. + +`android.view.View` + +: Used to type your app's view. + +`androidx.appcompat.app.AppCompatActivity` + +: Used to create your main activity. See the [`AppCompatActivity` documentation](https://developer.android.com/reference/androidx/appcompat/app/AppCompatActivity) for reference. + +`com.adjust.sdk.Adjust` + +: Used to access Adjust APIs. + +`com.adjust.sdk.AdjustDeeplink` + +: Used to create Adjust deep links. +{% /deflist %} + +```java +// MainActivity.java +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; +``` + +### Create a global application class {% #create-a-global-application-class %} + +The recommended way to register the Adjust Android Extension for Adobe Experience SDK is to use a global Android [Application class](http://developer.android.com/reference/android/app/Application.html). If you've not yet created an Application, follow these steps: + +1. Create a new class that extends `Application` in your `MainApp.java` file. + + {% codeblock title="MainApp.java" startLineNumber=13 %} + ```java + public class MainApp extends Application {} + ``` + {% /codeblock %} + +1. Open your `AndroidManifest.xml` and find the `` element. + +1. Add the name of your new class as an `android:name` attribute. In this example, the new `Application` class is named `MainApp`. + + ```xml + + + ``` + +1. Within your `Application` class, find or add the `onCreate` method. + + {% codeblock + title="MainApp.java" + highlight="{range: 2-5}" + startLineNumber=13 %} + ```java + public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + } + } + ``` + {% /codeblock %} + +### Configure the Adjust Extension {% #configure-the-adjust-extension %} + +Once you've created the `Application` class and called `onCreate`, follow these steps to configure the Adjust Android Extension for Adobe Experience SDK: + +1. Inside your `onCreate` function, call `MobileCore.setApplication(this)` to register the application context. + + {% codeblock + title="MainApp.java" + highlight="{range: 4}, {range: 11}" + startLineNumber=15 %} + ```java + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + } + ``` + {% /codeblock %} + +1. Set your logging level by calling the `MobileCore.setLogLevel` method with the following argument: + + {% deflist %} + `logLevel`: `String` + + : The level of logging you want to enable. + + - `LoggingMode.VERBOSE`: enable all logging. + - `LoggingMode.DEBUG`: disable verbose logging. + - `LoggingMode.WARNING`: log only errors and warnings. + - `LoggingMode.ERROR`: log only errors. + {% /deflist %} + + {% codeblock + title="MainApp.java" + highlight="{range:4-5}" + startLineNumber=15 %} + ```java + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + } + ``` + {% /codeblock %} + +1. Create a new `try...catch` block to configure the Adjust Extension: + + {% codeblock + title="MainApp.java" + highlight="{range: 7-10}" + startLineNumber=15 %} + ```java + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + } + ``` + {% /codeblock %} + +1. Within your `try` block, call `MobileCore.configureWithAppID` and pass your Adobe app ID. + + {% codeblock + title="MainApp.java" + highlight="{range: 2}" + startLineNumber=21 %} + ```java + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + ``` + {% /codeblock %} + +1. Within your `try` block, create a new instance of `AdjustAdobeExtensionConfig` with the following argument: + + {% deflist %} + `environment`: `String` + + : The environment in which your device is running. + + - Pass `AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX` when testing. + - Pass `AdjustAdobeExtensionConfig.ENVIRONMENT_PRODUCTION` when running the app in production. + {% /deflist %} + + {% codeblock + title="MainApp.java" + highlight="{range: 4-5}" + startLineNumber=21 %} + ```java + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + ``` + {% /codeblock %} + +1. Call `AdjustAdobeExtension.setConfiguration` with your `AdjustAdobeExtensionConfig` instance as an argument. + + {% codeblock + title="MainApp.java" + highlight="{range: 6}" + startLineNumber=21 %} + ```java + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + ``` + {% /codeblock %} + +### Register the Adjust Extension {% #register-the-adjust-extension %} + +Once you've configured the Adjust Extension, you need to register it with the Adobe Experience SDK. To do this: + +1. Create a new `try...catch` block below your configuration block. + + {% codeblock + title="MainApp.java" + highlight="{range: 19-22}" + startLineNumber=9 %} + ```java + public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } + } + ``` + {% /codeblock %} + +1. Within your `try` block, create a new list of the extensions you want to register. The example in this guide imports the `Analytics` and `Identity` extensions in addition to the `AdjustAdobeExtension`. + + {% deflist %} + `extensions`: `List>` + + : Your list of extensions. + {% /deflist %} + + {% codeblock + title="MainApp.java" + highlight="{range: 2-5}" + startLineNumber=27 %} + ```java + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + ``` + {% /codeblock %} + +1. Inside your `try` block, call the `MobileCore.registerExtensions` method with your list of extensions and the following callback argument: + + {% deflist %} + `completionCallback`: `AdobeCallback` + + : A callback function that fires when registration completes. + {% /deflist %} + + {% codeblock + title="MainApp.java" + highlight="{range: 6-10}" + startLineNumber=27 %} + ```java + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + ``` + {% /codeblock %} + +### Set up your activity file {% #set-up-your-activity-file %} + +Next, you need to set up your `MainActivity.java` file. You'll use this file to set up your Adjust features later. For the purposes of this guide, you're only going to set up the `onCreate` function to handle application startup. + +1. Create a new public class called `MainActivity`. This class should extend the `AppCompatActivity` class. + + {% codeblock title="MainActivity.java" startLineNumber=11 %} + ```java + public class MainActivity extends AppCompatActivity {} + ``` + {% /codeblock %} + +1. Create a new protected override function called `onCreate`. This function receives the `savedInstanceState` and returns `void`. + + {% codeblock + title="MainActivity.java" + highlight="{range: 2-3}" + startLineNumber=11 %} + ```java + public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) {} + } + ``` + {% /codeblock %} + +1. Within your `onCreate` function, call `super.onCreate` with the `savedInstanceState` to create your activity. + + {% codeblock + title="MainActivity.java" + highlight="{range: 3}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + } + ``` + {% /codeblock %} + +1. Next, call `setContentView` to map your activity to your app layout. In this example, the layout file is called `activity_main.xml`. + + {% codeblock + title="MainActivity.java" + highlight="{range: 4}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + } + ``` + {% /codeblock %} + +### Set up deep link handling {% #set-up-deep-link-handling %} + +To configure the Adjust Android Extension for Adobe Experience SDK to open deep links, follow these steps: + +1. Create a new `Intent` variable called `intent` inside your `onCreate` function and assign it the output of `getIntent()`. + + {% codeblock + title="MainActivity.java" + highlight="{range: 6}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + } + ``` + {% /codeblock %} + +1. Create a new `Uri` variable called `data` and assign it the output of `intent.getData()`. + + {% codeblock + title="MainActivity.java" + highlight="{range: 7}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + } + ``` + {% /codeblock %} + +1. Construct a new `AdjustDeeplink` instance with your `data` variable. + + {% codeblock + title="MainActivity.java" + highlight="{range: 8}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + } + ``` + {% /codeblock %} + +1. To open the URL, pass your `AdjustDeeplink` instance and `getApplicationContext()` to the `Adjust.processDeeplink` method. + + {% codeblock + title="MainActivity.java" + highlight="{range: 9}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + ``` + {% /codeblock %} + + If you use [short branded links](https://help.adjust.com/en/article/short-branded-links), you can alternatively use the `Adjust.processAndResolveDeeplink` method to resolve your shortened link and return it to a callback function. + + {% codeblock + title="MainActivity.java" + highlight="{range: 9-14}" + startLineNumber=12 %} + ```java + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processAndResolveDeeplink(adjustDeeplink, getApplicationContext(), new OnDeeplinkResolvedListener() { + @Override + public void onDeeplinkResolved(String s) { + Log.d("example", "Unwrapped short link: " + s); + } + }); + } + ``` + {% /codeblock %} + +Once you've completed these steps, build and run your app. In your log viewer, set the filter `tag:Adjust` to show only logs relating to the Adjust Extension. After you launch your app, you should see the message `Install tracked`. diff --git a/src/content/docs/en/sdk/adobe-extension/android/preinstalled.mdoc b/src/content/docs/en/sdk/adobe-extension/android/preinstalled.mdoc new file mode 100644 index 000000000..9a2fa5d12 --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/preinstalled.mdoc @@ -0,0 +1,130 @@ +--- +title: Send preinstalled app activity +sidebar-label: Configure preinstalled app +description: Configure a campaign to send information from preinstalled apps. +sidebar-position: 3 +--- + +You can use the Adjust Android Extension for Adobe Experience SDK to send Adjust activity from apps that came preinstalled on a user's device. This enables you to send information from users who didn't download your app from a campaign. + +You can send data from preinstalled apps to a predefined default link. When a user opens the app for the first time, the install session is associated with the default link token. + +## Reference {% #reference %} + +To set your default link token, call the `setDefaultTracker` method of your `AdjustAdobeExtensionConfig` instance with the following argument: + +{% deflist %} +`token`: `String` + +: Your alphanumeric Adjust link token. +{% /deflist %} + +## Tutorial: Set a default link token {% #tutorial %} + +To set your default link token, you need to add the token to your `AdjustAdobeExtensionConfig` instance. If you followed the [integration guide](/en/sdk/adobe-extension/android/integration), your `MainApp.java` file should look something like this: + +```java +// MainApp.java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; + +public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } +} +``` + +To set a default link token for preinstalled apps, pass the link token to the `setDefaultTracker` method of the `AdjustAdobeExtensionConfig` instance. When Adjust receives the install session information, it attributes the install to the default link. + +In this example, the default link token is set to `"abc123"`. + +{% codeblock title="MainApp.java" highlight="{range: 26}" %} +```java +import android.app.Application; +import android.util.Log; + +import com.adjust.adobeextension.AdjustAdobeExtension; +import com.adjust.adobeextension.AdjustAdobeExtensionConfig; +import com.adobe.marketing.mobile.AdobeCallback; +import com.adobe.marketing.mobile.Extension; +import com.adobe.marketing.mobile.Analytics; +import com.adobe.marketing.mobile.Identity; +import com.adobe.marketing.mobile.LoggingMode; +import com.adobe.marketing.mobile.MobileCore; + +public class MainApp extends Application { + @Override + public void onCreate() { + super.onCreate(); + + MobileCore.setApplication(this); + MobileCore.setLogLevel(LoggingMode.VERBOSE); + + try { + MobileCore.configureWithAppID("your_adobe_app_id"); + + AdjustAdobeExtensionConfig config = + new AdjustAdobeExtensionConfig(AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX); + config.setDefaultTracker("abc123"); + AdjustAdobeExtension.setConfiguration(config); + } catch (Exception e) { + Log.e("example", "Exception occurred during configuration: " + e.getMessage()); + } + + try { + List> extensions = Arrays.asList( + Analytics.EXTENSION, + Identity.EXTENSION, + AdjustAdobeExtension.EXTENSION); + MobileCore.registerExtensions(extensions, new AdobeCallback() { + @Override + public void call(Object o) { + Log.d("example", "Adjust Adobe Extension SDK initialized"); + } + }); + } catch (Exception e) { + Log.e("example", "Exception occurred while registering Extension: " + e.getMessage()); + } + } +} +``` +{% /codeblock %} diff --git a/src/content/docs/en/sdk/adobe-extension/android/push-tokens.mdoc b/src/content/docs/en/sdk/adobe-extension/android/push-tokens.mdoc new file mode 100644 index 000000000..4788ff505 --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/android/push-tokens.mdoc @@ -0,0 +1,184 @@ +--- +title: Send push tokens +description: Send push tokens to Adjust to inform audiences and uninstall and reinstall measurement. +sidebar-position: 8 +--- + +Push notifications enable you to deliver personalized content to your users. You can use deep links to direct users to specific pages in your app, and measure reattributions. + +- The push token is a unique identifier that can be used to sort [Audiences](https://help.adjust.com/en/article/audiences) and client callbacks. +- Push tokens are also required for [uninstall and reinstall measurement](https://help.adjust.com/en/article/uninstalls-reinstalls). + +## How it works {% #how-it-works %} + +Each device generates a unique push token that's used to target it. The push token is sent to Adjust when the following information is passed to the `MobileCore.trackAction` API: + +1. `AdjustAdobeExtension.ADOBE_ADJUST_ACTION_SET_PUSH_TOKEN`: a string constant that maps to the `setPushToken` method. +1. `contextData`: a HashMap of values used to configure your push token. + +When you call `MobileCore.trackAction` with these arguments, the Adjust extension the token to the `setPushToken` method and sends the information to Adjust. + +## Reference {% #reference %} + +The `contextData` HashMap holds information about an action. To configure your push token, add the following key-value pair to your HashMap. + +{% deflist %} +`AdjustAdobeExtension.ADOBE_ADJUST_PUSH_TOKEN` + +: The device's push token. +{% /deflist %} + +## Example: Send a push token {% #example-send-push-token %} + +To send a push token to Adjust, you need to add a function to your main activity. In this tutorial, you'll build on `MainActivity.java` from the [integration guide](/en/sdk/adobe-extension/android/integration) and add a new function called `sendPushTokenToAdjust` which will send an updated push token to Adjust. The final result looks like this: + +```java +// MainActivity.java +import android.content.Intent; +import android.net.Uri; +import android.os.Bundle; +import android.view.View; + +import androidx.appcompat.app.AppCompatActivity; + +import com.adjust.sdk.Adjust; +import com.adjust.sdk.AdjustDeeplink; +import com.adobe.marketing.mobile.MobileCore; + +import java.util.HashMap; +import java.util.Map; + +public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + + public void sendPushTokenToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_PUSH_TOKEN, "de18dbf8-f38a-4962-8f1e-44abcf43055d"); + + MobileCore.trackAction(action, contextData); + } +} +``` + +Here's what you need to do: + +1. First, import the following classes: + + - `com.adobe.marketing.mobile.MobileCore`: this class is used to send information to Adobe and Adjust. + - `java.util.HashMap`: this class is used to generate the `contextData` HashMap. + - `java.util.Map`: this class is used to type the `contextData` HashMap. + + {% codeblock + title="MainActivity.java" + highlight="{range: 10}, {range: 12-13}" %} + ```java + import android.content.Intent; + import android.net.Uri; + import android.os.Bundle; + import android.view.View; + + import androidx.appcompat.app.AppCompatActivity; + + import com.adjust.sdk.Adjust; + import com.adjust.sdk.AdjustDeeplink; + import com.adobe.marketing.mobile.MobileCore; + + import java.util.HashMap; + import java.util.Map; + ``` + {% /codeblock %} + +1. Next, create a new function inside the `MainActivity` class called `sendPushTokenToAdjust`. This function takes [a `View`](https://developer.android.com/reference/android/view/View) as an argument and returns `void.` + + {% codeblock + title="MainActivity.java" + highlight="{range: 13}" + startLineNumber=15 %} + ```java + public class MainActivity extends AppCompatActivity { + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + Intent intent = getIntent(); + Uri data = intent.getData(); + AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); + Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); + } + + public void sendPushTokenToAdjust(View view) {} + } + ``` + {% /codeblock %} + +1. Inside the `sendPushTokenToAdjust` function, declare a new `String` variable called `action` and assign it the value `AdjustAdobeExtension.ADOBE_ADJUST_ACTION_SET_PUSH_TOKEN`. This is used to tell `MobileCore.trackAction` which action to handle. + + {% codeblock + title="MainActivity.java" + highlight="{range: 2}" + startLineNumber=27 %} + ```java + public void sendPushTokenToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_SET_PUSH_TOKEN; + } + ``` + {% /codeblock %} + +1. Create a new HashMap variable called `contextData`. This is used to hold the properties of the action. + + {% codeblock + title="MainActivity.java" + highlight="{range: 3}" + startLineNumber=27 %} + ```java + public void sendPushTokenToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_SET_PUSH_TOKEN; + Map contextData = new HashMap(); + } + ``` + {% /codeblock %} + +1. Add your push token to the HashMap using the `AdjustAdobeExtension.ADOBE_ADJUST_PUSH_TOKEN` key. This example sets the push token to `"de18dbf8-f38a-4962-8f1e-44abcf43055d"`. + + {% codeblock + title="MainActivity.java" + highlight="{range: 4}" + startLineNumber=27 %} + ```java + public void sendPushTokenToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_PUSH_TOKEN, "de18dbf8-f38a-4962-8f1e-44abcf43055d"); + } + ``` + {% /codeblock %} + +1. Finally, call `MobileCore.trackAction` with your `action` and `contextData` variables to send the push token to Adjust. + + {% codeblock + title="MainActivity.java" + highlight="{range: 6}" + startLineNumber=27 %} + ```java + public void sendPushTokenToAdjust(View view) { + String action = AdjustAdobeExtension.ADOBE_ADJUST_ACTION_TRACK_EVENT; + Map contextData = new HashMap(); + contextData.put(AdjustAdobeExtension.ADOBE_ADJUST_PUSH_TOKEN, "de18dbf8-f38a-4962-8f1e-44abcf43055d"); + + MobileCore.trackAction(action, contextData); + } + ``` + {% /codeblock %} + +That's it! When the user performs an action that maps to the `sendPushTokenToAdjust` function, your push token is sent to Adjust. diff --git a/src/content/docs/en/sdk/adobe-extension/index.mdoc b/src/content/docs/en/sdk/adobe-extension/index.mdoc new file mode 100644 index 000000000..62c27dcde --- /dev/null +++ b/src/content/docs/en/sdk/adobe-extension/index.mdoc @@ -0,0 +1,8 @@ +--- +title: Adjust Extension for Adobe Experience SDK +description: Use the Adjust Extension for Adobe Experience SDK to access Adjust's features in your Adobe Experience apps +sidebar-label: Adobe Experience Extension +sidebar-position: 11 +type: category +--- + diff --git a/src/content/docs/en/sdk/migration/adobe-extension/android/index.mdoc b/src/content/docs/en/sdk/migration/adobe-extension/android/index.mdoc new file mode 100644 index 000000000..1716b6459 --- /dev/null +++ b/src/content/docs/en/sdk/migration/adobe-extension/android/index.mdoc @@ -0,0 +1,229 @@ +--- +title: Android Adobe Extension v3 migration guide +description: Follow this guide to migrate from v2 to v3 +sidebar-label: Android v3 migration guide +sidebar-position: 1 +--- + +The [Adjust Extension for Adobe Experience SDK](https://github.com/adjust/android_adobe_extension) has been updated to v3 to support Adjust Android SDK v5. Follow this guide to migrate from v2 to v3. + +{% callout type="important" %} +You need to update your app to support [Android API 21](https://developer.android.com/tools/releases/platforms#5.0) or above before migrating. +{% /callout %} + +To install v3 of the Adjust Android Extension for Adobe Experience, update the dependency declarations in your `build.gradle` as follows: + +1. `com.adjust.adobeextension:adobeextension` MUST be updated to 3.0.0 or later. +1. `com.adjust.sdk:adjust-android` MUST be updated to 5.0.0 or later. + +```groovy +dependencies { + implementation 'com.adjust.adobeextension:adobeextension:{% $versions.android_adobe_extension.v3 %}' + implementation 'com.adjust.sdk:adjust-android:{% $versions.android.v5 %}' + implementation 'com.adobe.marketing.mobile:core:3.2.0' + implementation 'com.android.installreferrer:installreferrer:2.2' +} +``` + +For a complete guide to setting up the Adjust Android Extension for Adobe Experience, see the [integration guide](/en/sdk/adobe-extension/android/integration). + +## New APIs {% #new-apis %} + +{% minorversion added="v3" size="large" /%} + +The following APIs have been added in v3. + +### Resolve short branded links {% #resolve-short-branded-links %} + +v3 of the Adjust Extension for Adobe Experience SDK adds support for resolving [short branded links](https://help.adjust.com/en/article/short-branded-links). To resolve shortened links, call the `Adjust.processAndResolveDeeplink` method with the following arguments: + +{% deflist %} +`adjustDeeplink`: `AdjustDeeplink` + +: The deep link that opened the app. + +`context`: `Context` + +: The app context. Call `getApplicationContext()` to fill this value. + +`callback`: `OnDeeplinkResolvedListener` + +: A callback function that receives the resolved short link as an argument. +{% /deflist %} + +```java +Intent intent = getIntent(); +Uri data = intent.getData(); +AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); +Adjust.processAndResolveDeeplink(adjustDeeplink, getApplicationContext(), new OnDeeplinkResolvedListener() { + @Override + public void onDeeplinkResolved(String s) { + + } +}); +``` + +### Global callback parameters {% #global-callback-parameters %} + +v3 of the Adjust Extension for Adobe Experience SDK adds support for the global callback parameters API from Android SDK v5. To add global callbacks to your sessions, call the `Adjust.addGlobalCallbackParameter` method with the following arguments: + +{% deflist %} +`key`: `String` + +: The key of your parameter. + +`value`: `String` + +: The value of your parameter. +{% /deflist %} + +```java +Adjust.addGlobalCallbackParameter("key", "value"); +Adjust.addGlobalCallbackParameter("user_id", "855"); +``` + +Learn how to [set up global callback](/en/sdk/adobe-extension/android/global-parameters#global-callback-parameters). + +### Global partner parameters {% #global-partner-parameters %} + +v3 of the Adjust Extension for Adobe Experience SDK adds support for the global partner parameters API from Android SDK v5. To add global partner parameters, call the `Adjust.addGlobalPartnerParameter` method with the following arguments: + +{% deflist %} +`key`: `String` + +: The key of your parameter. + +`value`: `String` + +: The value of your parameter. +{% /deflist %} + +```java +Adjust.addGlobalPartnerParameter("key", "value"); +Adjust.addGlobalPartnerParameter("user_id", "855"); +``` + +Learn how to [set up global partner parameters](/en/sdk/adobe-extension/android/global-parameters#global-partner-parameters). + +### Set external device ID {% #set-external-device-id %} + +v3 of the Adjust Extension for Adobe Experience SDK adds support for setting [external device identifiers](https://help.adjust.com/en/article/external-device-identifiers). To set an external device ID, call the `setExternalDeviceId` method of your `AdjustAdobeExtensionConfig` instance with the following argument: + +{% deflist %} +`externalDeviceId`: `String` + +: Your external device identifier. +{% /deflist %} + +```java +String environment = AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX; +AdjustAdobeExtensionConfig config = new AdjustAdobeExtensionConfig(environment); +config.setExternalDeviceId("{YourExternalDeviceId}"); +AdjustAdobeExtension.setConfiguration(config); +``` + +Learn how to [configure external device IDs](/en/sdk/adobe-extension/android/external-device-id). + +### Set default link token for preinstalled apps {% #set-default-link-token-preinstalled-apps %} + +v3 of the Adjust Extension for Adobe Experience SDK adds support for setting a default [link token](https://help.adjust.com/en/article/links) for recording preinstalled app installs to a default campaign. To set a default link token, call the `setDefaultTracker` method of your `AdjustAdobeExtensionConfig` instance with the following argument: + +{% deflist %} +`defaultTracker`: `String` + +: The alphanumeric link token of your preinstall campaign. +{% /deflist %} + +```java +String environment = AdjustAdobeExtensionConfig.ENVIRONMENT_SANDBOX; +AdjustAdobeExtensionConfig config = new AdjustAdobeExtensionConfig(environment); +config.setDefaultTracker("{Token}"); +AdjustAdobeExtension.setConfiguration(config); +``` + +Learn how to [send preinstalled app activity](/en/sdk/adobe-extension/android/preinstalled). + +## Changed APIs {% #changed-apis %} + +{% minorversion changed="v3" size="large" /%} + +The following APIs have changed in v3. + +### Retrieve device ADID {% #retrieve-device-adid %} + +In SDK v2, the `AdjustAttribution` class has a property called `adid`. This property has been removed. You can retrieve the device's ADID asynchronously, by calling `Adjust.getAdid`. + +```java +Adjust.getAdid(new OnAdidReadListener() { + @Override + public void onAdidRead(String adid) { + // Your callback function + } +}); +``` + +### Direct deep linking {% #direct-deep-linking %} + +In SDK v2, you can open deep links for attribution by calling the `AdjustAdobeExtension.openUrl` method with the deep link data as an argument. + +```java +Intent intent = getIntent(); +Uri data = intent.getData(); +AdjustAdobeExtension.openUrl(data, getApplicationContext()); +``` + +SDK v3 has been updated to use the Adjust Android SDK's `processDeeplink` method. To open direct deep links: + +1. Create a new `AdjustDeeplink` instance with the deep link URL. +1. Pass your `AdjustDeeplink` instance to the `Adjust.processDeeplink` method. + +```java +Intent intent = getIntent(); +Uri data = intent.getData(); +AdjustDeeplink adjustDeeplink = new AdjustDeeplink(data); +Adjust.processDeeplink(adjustDeeplink, getApplicationContext()); +``` + +Learn how to [reattribute users with direct deep links](/en/sdk/adobe-extension/android/deep-linking#reattribute-users-with-direct-deep-links). + +### Deferred deep linking callback {% #deferred-deep-linking-callback %} + +In SDK v2, you can configure the SDK to launch a callback function when a deferred deep link is opened by passing a function to the `setOnDeeplinkResponseListener` method of your `AdjustAdobeExtensionConfig` instance. + +```java +AdjustAdobeExtensionConfig config = new AdjustAdobeExtensionConfig(environment); + +config.setOnDeeplinkResponseListener(new OnDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +AdjustAdobeExtension.setConfiguration(config); +``` + +In SDK v3, the `setOnDeeplinkResponseListener` method has been renamed to `setOnDeferredDeeplinkResponseListener`. + +```java +AdjustAdobeExtensionConfig config = new AdjustAdobeExtensionConfig(environment); + +config.setOnDeferredDeeplinkResponseListener(new OnDeferredDeeplinkResponseListener() { + @Override + public boolean launchReceivedDeeplink(Uri deeplink) { + if (shouldAdjustSdkLaunchTheDeeplink(deeplink)) { + return true; + } else { + return false; + } + } +}); + +AdjustAdobeExtension.setConfiguration(config); +``` + +Learn how to [work with deferred deep link callbacks](/en/sdk/adobe-extension/android/deep-linking#deferred-deep-link-callbacks). diff --git a/src/content/docs/en/sdk/migration/adobe-extension/index.mdoc b/src/content/docs/en/sdk/migration/adobe-extension/index.mdoc new file mode 100644 index 000000000..36dbd925d --- /dev/null +++ b/src/content/docs/en/sdk/migration/adobe-extension/index.mdoc @@ -0,0 +1,8 @@ +--- +title: Adjust Extension for Adobe Experience SDK +sidebar-label: Adobe Extension +description: Follow these guides to migrate between SDK versions +type: category +sidebar-position: 7 +--- + diff --git a/src/content/docs/en/sdk/migration/index.mdx b/src/content/docs/en/sdk/migration/index.mdx index 241895927..6dfb875d0 100644 --- a/src/content/docs/en/sdk/migration/index.mdx +++ b/src/content/docs/en/sdk/migration/index.mdx @@ -2,6 +2,6 @@ title: Migration guides description: Follow these guides to migrate between SDK versions slug: en/sdk/migration -sidebar-position: 12 +sidebar-position: 13 type: category --- diff --git a/src/content/docs/en/sdk/testing/index.mdx b/src/content/docs/en/sdk/testing/index.mdx index 9fc5ec409..6f972a033 100644 --- a/src/content/docs/en/sdk/testing/index.mdx +++ b/src/content/docs/en/sdk/testing/index.mdx @@ -2,7 +2,7 @@ title: "Testing guide" description: "Test your Adjust SDK integration using Adjust's testing tools" slug: en/sdk/testing -sidebar-position: 11 +sidebar-position: 12 --- Once you've set up the Adjust SDK in your app, you should test it to make sure everything is working. Adjust provides a testing console you can use to see information passed from your test device to Adjust's servers. diff --git a/src/declarations.d.ts b/src/declarations.d.ts index a47a3f81d..6c8351061 100644 --- a/src/declarations.d.ts +++ b/src/declarations.d.ts @@ -28,13 +28,19 @@ declare interface VersionProps { version: string; } -declare interface VersionMap { - [key: string]: string | { - v4: string; - v5: string; - }; +interface VersionTag { + [versionKey: string]: string; } +interface PlatformVersion { + versions: VersionTag | string; + useSdkSuffix: boolean; +} + +type VersionMap = { + [platform: string]: PlatformVersion; +}; + declare type BadgeColor = | "neutral" | "negative" diff --git a/src/integrations/fetchSdkVersions.ts b/src/integrations/fetchSdkVersions.ts index 3f4cd6a90..947a5390b 100644 --- a/src/integrations/fetchSdkVersions.ts +++ b/src/integrations/fetchSdkVersions.ts @@ -2,32 +2,17 @@ import { Octokit } from "@octokit/core"; const octokit = new Octokit({ auth: import.meta.env.VITE_GITHUB_TOKEN }); -type TagNode = { - node: { - name: string; - }; +// Define type for SDK versions with multiple tags (v4, v5, etc.) +type MultiVersionTags = { + [versionKey: string]: string; }; -// Define the shape of the GraphQL response -type GraphQLResponse = { - v4Tags: { - refs: { - edges: TagNode[]; - }; - }; - v5Tags: { - refs: { - edges: TagNode[]; - }; - }; - latestTag?: { - refs: { - edges: TagNode[]; - }; - }; +// Define the main type for the version replacements +type VersionReplacements = { + [platform: string]: MultiVersionTags | string; }; -let versionReplacements: VersionMap = { +const versionReplacements: VersionReplacements = { android: { v4: "x.x.x", v5: "x.x.x" }, ios: { v4: "x.x.x", v5: "x.x.x" }, unity: { v4: "x.x.x", v5: "x.x.x" }, @@ -35,86 +20,109 @@ let versionReplacements: VersionMap = { cordova: { v4: "x.x.x", v5: "x.x.x" }, flutter: { v4: "x.x.x", v5: "x.x.x" }, cocos2dx: { v4: "x.x.x", v5: "x.x.x" }, + android_adobe_extension: { v2: "x.x.x", v3: "x.x.x" }, web: "x.x.x", windows: "x.x.x", }; +type TagNode = { + node: { + name: string; + }; +}; + +type VersionTagResponse = { + refs: { + edges: TagNode[]; + }; +}; + +// GraphQL response with dynamic keys for each version query +type GraphQLResponse = { + [key: string]: VersionTagResponse; +}; + /** - * Queries the GitHub GraphQL endpoint for the latest versioned tag of each platform - * @returns A VersionMap of the latest versions of each SDK + * Queries the GitHub GraphQL endpoint for the latest versioned tags of each SDK platform. + * @returns A map of SDK platforms and their latest tags for each version. */ export async function fetchVersions() { try { if (import.meta.env.PROD) { - const fetchPromises = Object.keys(versionReplacements).map( - async (platform) => { - const currentPlatform = versionReplacements[platform]; - if (typeof currentPlatform === "object") { + const fetchPromises = Object.entries(versionReplacements).map( + async ([platform, versions]) => { + const useSdkSuffix = !["android_adobe_extension"] + .includes(platform); + const repoName = `${platform}${useSdkSuffix ? "_sdk" : ""}`; + + if (typeof versions === "object") { + // For platforms with multiple versions (v4, v5, etc.) + const versionQueries = Object.keys(versions) + .map( + (versionKey) => ` + ${versionKey}Tags: repository(owner: "adjust", name: "${repoName}") { + refs( + refPrefix: "refs/tags/" + orderBy: { field: TAG_COMMIT_DATE, direction: DESC } + first: 1 + query: "${versionKey}" + ) { + edges { + node { + name + } + } + } + } + `, + ) + .join("\n"); + const query = ` - query RepositoryTags { - v4Tags: repository(owner: "adjust", name: "${platform}_sdk") { - refs( - refPrefix: "refs/tags/" - orderBy: { field: TAG_COMMIT_DATE, direction: DESC } - first: 1 - query: "v4" - ) { - edges { - node { - name - } - } - } - } - v5Tags: repository(owner: "adjust", name: "${platform}_sdk") { - refs( - refPrefix: "refs/tags/" - orderBy: { field: TAG_COMMIT_DATE, direction: DESC } - first: 1 - query: "v5" - ) { - edges { - node { - name - } - } - } - } - } - `; + query RepositoryTags { + ${versionQueries} + } + `; const response = await octokit.graphql(query); - // Extract the first v4 and v5 tag names - const firstV4Tag = response.v4Tags.refs.edges[0]?.node.name.replace("v", "") || "Not found"; - const firstV5Tag = response.v5Tags.refs.edges[0]?.node.name.replace("v", "") || "Not found"; - - currentPlatform.v4 = firstV4Tag; - currentPlatform.v5 = firstV5Tag; + // Update each version tag in the output map + Object.keys(versions).forEach((versionKey) => { + const tag = + response[`${versionKey}Tags`]?.refs.edges[0]?.node.name.replace( + "v", + "", + ) || "Not found"; + (versionReplacements[platform] as MultiVersionTags)[versionKey] = + tag; + }); } else { + // For platforms with a single latest tag (no version keys like v4, v5) const query = ` - query RepositoryTags { - latestTag: repository(owner: "adjust", name: "${platform}_sdk") { - refs( - refPrefix: "refs/tags/" - orderBy: { field: TAG_COMMIT_DATE, direction: DESC } - first: 1 - query: "v" - ) { - edges { - node { - name - } - } - } - } - } - `; + query RepositoryTags { + latestTag: repository(owner: "adjust", name: "${repoName}") { + refs( + refPrefix: "refs/tags/" + orderBy: { field: TAG_COMMIT_DATE, direction: DESC } + first: 1 + query: "v" + ) { + edges { + node { + name + } + } + } + } + } + `; const response = await octokit.graphql(query); - versionReplacements[platform] = response.latestTag?.refs.edges[0]?.node.name.replace("v", "") || "Not found"; + versionReplacements[platform] = + response.latestTag?.refs.edges[0]?.node.name.replace("v", "") || + "x.x.x"; } - } + }, ); await Promise.all(fetchPromises); diff --git a/src/utils/helpers/navigation/buildSidebarHierarchy.ts b/src/utils/helpers/navigation/buildSidebarHierarchy.ts index 1cea02da6..d98fcf938 100644 --- a/src/utils/helpers/navigation/buildSidebarHierarchy.ts +++ b/src/utils/helpers/navigation/buildSidebarHierarchy.ts @@ -1,5 +1,9 @@ // Import necessary types -import type { ContentCollectionEntry, LanguageTree, SidebarItem } from "@utils/helpers/navigation/types"; +import type { + ContentCollectionEntry, + LanguageTree, + SidebarItem, +} from "@utils/helpers/navigation/types"; const versionRegex = /v\d/i; /** @@ -8,7 +12,9 @@ const versionRegex = /v\d/i; * @returns A LanguageTree containing SidebarItem entries for API and SDK content. * @returns A hashmap of all entries provided for easier querying. */ -export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [LanguageTree, Map] => { +export const buildSidebarHierarchy = ( + entries: ContentCollectionEntry[], +): [LanguageTree, Map] => { // Initialize arrays for SDK and API content const hierarchy = { sdk: [] as SidebarItem[], @@ -22,9 +28,17 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu const slugMap = new Map(); // Populate the slugMap with SidebarItems - sortedEntries.forEach(entry => { + sortedEntries.forEach((entry) => { const { id, slug, data } = entry; - const { title, description, "sidebar-label": label, "sidebar-position": position, "category-title": categoryTitle, type, redirects } = data; + const { + title, + description, + "sidebar-label": label, + "sidebar-position": position, + "category-title": categoryTitle, + type, + redirects, + } = data; slugMap.set(entry.slug, { id, title, @@ -37,7 +51,7 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu type, version: "", level: 0, - redirects + redirects, }); }); @@ -47,7 +61,7 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu * @returns A version string or null */ const extractVersionFromSlug = (id: string): string | undefined => { - const idParts = id.split('/'); + const idParts = id.split("/"); // If content is versioned, it will always be at the 3rd position const versionIndex = 3; const matchedVersion = versionRegex.exec(idParts[versionIndex]); @@ -60,7 +74,7 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu * @param level The level of the parent (children will have parent level + 1) */ const setChildLevels = (parent: SidebarItem, level: number) => { - parent.children?.forEach(child => { + parent.children?.forEach((child) => { // Set the child to one level under the parent child.level = level + 1; setChildLevels(child, child.level); @@ -68,26 +82,30 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu }; // Build the parent-child relationships - sortedEntries.forEach(entry => { + sortedEntries.forEach((entry) => { // Fetch the entry from the slug map const structuredEntry = slugMap.get(entry.slug)!; - const slugParts = entry.slug.split('/'); + const slugParts = entry.slug.split("/"); // Check the slug to see if the entry is an api or sdk entry const type = slugParts[1]; // Extract version from the entry id - structuredEntry.version = extractVersionFromSlug(structuredEntry.id) || undefined; + structuredEntry.version = extractVersionFromSlug(structuredEntry.id) || + undefined; // Find potential children by checking if the slug is a direct parent slugMap.forEach((potentialChild, potentialChildSlug) => { - if (!potentialChildSlug.startsWith(entry.slug + "/") || potentialChild.parent) { + if ( + !potentialChildSlug.startsWith(entry.slug + "/") || + potentialChild.parent + ) { // Skip if child doesn't start with the parent slug or already has a parent return; } - const parentSlugParts = entry.slug.split('/'); - const parentIdParts = entry.id.split('/'); - const childSlugParts = potentialChild.slug.split('/'); + const parentSlugParts = entry.slug.split("/"); + const parentIdParts = entry.id.split("/"); + const childSlugParts = potentialChild.slug.split("/"); // Special case: Handle index pages in versioned folders let isSpecialCase = false; @@ -101,26 +119,28 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu } // Normal case: the child is one level deeper than the parent - const isDirectChild = childSlugParts.length === parentSlugParts.length + 1; + const isDirectChild = + childSlugParts.length === parentSlugParts.length + 1; // Assign child only if it's a direct child or matches the special case - if ((isSpecialCase || isDirectChild) && potentialChildSlug.startsWith(entry.slug + '/') && potentialChildSlug !== entry.slug) { - // Only set the parent if it doesn't already have one to avoid double nesting + if ( + (isSpecialCase || isDirectChild) && + potentialChildSlug.startsWith(entry.slug + "/") && + potentialChildSlug !== entry.slug + ) { if (!potentialChild.parent) { potentialChild.parent = entry.slug; + structuredEntry.children?.push(potentialChild); - // Insert the child in the correct position or alphabetically - if (potentialChild.position) { - structuredEntry.children?.splice(potentialChild.position - 1, 0, potentialChild); - } else { - structuredEntry.children?.push(potentialChild); - } - - // Remove the entry from the root hierarchy since it's now a child + // Remove the entry from the root hierarchy if (type === "sdk") { - hierarchy.sdk = hierarchy.sdk.filter(item => item.slug !== potentialChild.slug); + hierarchy.sdk = hierarchy.sdk.filter((item) => + item.slug !== potentialChild.slug + ); } else if (type === "api") { - hierarchy.api = hierarchy.api.filter(item => item.slug !== potentialChild.slug); + hierarchy.api = hierarchy.api.filter((item) => + item.slug !== potentialChild.slug + ); } } } @@ -128,19 +148,19 @@ export const buildSidebarHierarchy = (entries: ContentCollectionEntry[]): [Langu // Sort the children alphabetically if they have no position structuredEntry.children?.sort((a, b) => { - if (a.position && b.position) { - return 0; + if (a.position !== undefined && b.position !== undefined) { + return a.position - b.position; } - if (a.position) { + if (a.position !== undefined) { return -1; } - if (b.position) { + if (b.position !== undefined) { return 1; } - // Sort alphabetically by file name (last part of the id) - const aFileName = a.id.split('/').pop()?.toLowerCase(); - const bFileName = b.id.split('/').pop()?.toLowerCase(); - return aFileName?.localeCompare(bFileName!); + // Sort alphabetically by file name if positions are not defined + const aFileName = a.id.split("/").pop()?.toLowerCase() || ""; + const bFileName = b.id.split("/").pop()?.toLowerCase() || ""; + return aFileName.localeCompare(bFileName); }); // If the entry has no parent, add it to the top level