Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native Expo #48

Open
csirak opened this issue Feb 23, 2022 · 8 comments
Open

React Native Expo #48

csirak opened this issue Feb 23, 2022 · 8 comments

Comments

@csirak
Copy link

csirak commented Feb 23, 2022

Objects return as null

@ansh
Copy link

ansh commented Dec 12, 2022

Did you create a config plugin to get it to work? @csirak1528

@csirak
Copy link
Author

csirak commented Mar 14, 2023

no. it does not work with expo

@ansh
Copy link

ansh commented Mar 14, 2023

I created one and it works

@csirak
Copy link
Author

csirak commented Mar 14, 2023

where is it?

@BarakChamo
Copy link

@ansh are you able to share your config plugin?

@77zv
Copy link

77zv commented Jul 13, 2024

This is @ansh plugin from another thread:
expo/config-plugins#153

@77zv
Copy link

77zv commented Jul 14, 2024

For ios, I made the following plugin and it seems to work.
https://docs.snap.com/snap-kit/creative-kit/Tutorials/react-native
snapchat-plugin.js

module.exports = function withSnapchat(
  config,
  { snapchatClientId},
) {
  if (!config.ios) {
    config.ios = {};
  }
  if (!config.ios.infoPlist) {
    config.ios.infoPlist = {};
  }

  config.ios.infoPlist["LSApplicationQueriesSchemes"] = [
    "snapchat",
    "bitmoji-sdk",
    "itms-apps",
  ];
  config.ios.infoPlist["SCSDKClientId"] = snapchatClientId;
  config.ios.infoPlist["SCSDKRedirectUrl"] = "refer to creative kit react native docs for this";
  config.ios.infoPlist["URL Types / Document Role"] = "Editor";
  config.ios.infoPlist["URL Types / URL Identifier"] = "refer to creative kit react native docs for this";
  config.ios.infoPlist["URL Types / URL Schemes "] ="refer to creative kit react native docs for this";

  return config;
};

app.config.ts

...
plugins: [
    ["./snapchat-plugin", { snapchatClientId: "Public OAuth 2.0 Client ID" }],
    ...
    ]

@ansh
Copy link

ansh commented Jul 14, 2024

Here is mine. You have to replace com.example and PUBLIC_CLIENT_ID

Here is my config plugin. This works and is updated. You have to compile it to JS though.

```ts
import {
  AndroidConfig,
  createRunOncePlugin,
  ConfigPlugin,
  withProjectBuildGradle,
  withAndroidManifest,
  XML,
  withDangerousMod,
} from "@expo/config-plugins";
import {
  createGeneratedHeaderComment,
  MergeResults,
  mergeContents,
  removeGeneratedContents,
} from "@expo/config-plugins/build/utils/generateCode";
import { ExpoConfig } from "expo/config";
import * as fs from "fs-extra";
const { addMetaDataItemToMainApplication, getMainApplicationOrThrow } = AndroidConfig.Manifest;

// Fork of config-plugins mergeContents, but appends the contents to the end of the file. Taken from https://github.com/expo/expo/blob/master/packages/expo-camera/plugin/src/withCamera.ts
function appendContents({
  src,
  newSrc,
  tag,
  comment,
}: {
  src: string;
  newSrc: string;
  tag: string;
  comment: string;
}): MergeResults {
  const header = createGeneratedHeaderComment(newSrc, tag, comment);
  if (!src.includes(header)) {
    // Ensure the old generated contents are removed.
    const sanitizedTarget = removeGeneratedContents(src, tag);
    const contentsToAdd = [
      // @something
      header,
      // contents
      newSrc,
      // @end
      `${comment} @generated end ${tag}`,
    ].join("\n");

    return {
      contents: sanitizedTarget ?? src + contentsToAdd,
      didMerge: true,
      didClear: !!sanitizedTarget,
    };
  }
  return { contents: src, didClear: false, didMerge: false };
}

const PUBLIC_CLIENT_ID = "your-client-id-here";
const ANDROID_PACKAGE_NAME = "com.example.app";

const pkg = require("@snapchat/snap-kit-react-native/package.json");

const addSnapkitImport = (src: string): MergeResults => {
  return appendContents({
    tag: "expo-snapkit-import",
    src,
    newSrc: `allprojects { repositories { maven { url "https://storage.googleapis.com/snap-kit-build/maven" } } }`,
    comment: "//",
  });
};
const withSnapkitGradle: ConfigPlugin = (config) => {
  return withProjectBuildGradle(config, (config) => {
    if (config.modResults.language === "groovy") {
      config.modResults.contents = addSnapkitImport(config.modResults.contents).contents;
    } else {
      throw new Error(
        "Cannot add Snapkit maven gradle because the project build.gradle is not groovy"
      );
    }
    return config;
  });
};

async function addMetaDataToAndroidManifest(
  config: Pick<ExpoConfig, "android">,
  androidManifest: AndroidConfig.Manifest.AndroidManifest
): Promise<AndroidConfig.Manifest.AndroidManifest> {
  const name = "com.snapchat.kit.sdk.clientId";
  const value = PUBLIC_CLIENT_ID;
  const mainApplication = getMainApplicationOrThrow(androidManifest); // Get the <application /> tag and assert if it doesn't exist.
  addMetaDataItemToMainApplication(
    mainApplication,
    name, // value for `android:name`
    value // value for `android:value`
  );
  return androidManifest;
}
const withCustomMetaData: ConfigPlugin = (config) => {
  return withAndroidManifest(config, async (config) => {
    // Modifiers can be async, but try to keep them fast.
    config.modResults = await addMetaDataToAndroidManifest(config, config.modResults);
    return config;
  });
};

function addProviderToAndroidManifest(androidManifest: AndroidConfig.Manifest.AndroidManifest) {
  const app = AndroidConfig.Manifest.getMainApplicationOrThrow(
    androidManifest
  ) as AndroidConfig.Manifest.ManifestApplication & { provider?: any[] };
  // Add the provider if it doesn't exist.
  if (!app.provider) {
    app.provider = [];
  }
  // if the provider doesn't have the FileProvider, add it.
  if (!app.provider.some((p) => p.$["android:name"] === "androidx.core.content.FileProvider")) {
    // <provider android:authorities="com.example.fileprovider" android:name="androidx.core.content.FileProvider" android:exported="false" android:grantUriPermissions="true"><meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths"/></provider>
    app.provider.push({
      $: {
        "android:name": "androidx.core.content.FileProvider",
        "android:authorities": `${ANDROID_PACKAGE_NAME}.fileprovider`,
        "android:exported": "false",
        "android:grantUriPermissions": "true",
      },
      "meta-data": {
        $: {
          "android:name": "android.support.FILE_PROVIDER_PATHS",
          "android:resource": "@xml/file_paths",
        },
      },
    });
  }
  return androidManifest;
}
function withProvider(config: ExpoConfig) {
  return withAndroidManifest(config, async (config) => {
    config.modResults = addProviderToAndroidManifest(config.modResults);
    return config;
  });
}

function addPackageToQuery(androidManifest: AndroidConfig.Manifest.AndroidManifest) {
  // <package android:name="com.snapchat.android" />
  const PACKAGE_NAME = "com.snapchat.android";
  const packageToAdd = {
    package: {
      $: {
        "android:name": PACKAGE_NAME,
      },
    },
  };
  // @ts-ignore since queries does exist but Expo's types don't have it.
  const queries = androidManifest.manifest.queries;
  if (!queries) {
    // @ts-ignore since queries does exist but Expo's types don't have it.
    androidManifest.manifest.queries = [...packageToAdd];
  } else {
    // @ts-ignore
    const existingQuery = androidManifest.manifest.queries[0];
    const existingPackage = existingQuery.package;
    if (existingPackage) {
      const alreadyExists = existingPackage.some(
        (pkg: any) => pkg.$["android:name"] === PACKAGE_NAME
      );
      if (alreadyExists) return androidManifest;
      existingPackage.push(packageToAdd.package);
    } else {
      existingQuery.package = [
        {
          $: { ...packageToAdd.package.$ },
        },
      ];
    }
  }

  return androidManifest;
}
function withPackage(config: ExpoConfig) {
  return withAndroidManifest(config, async (config) => {
    config.modResults = addPackageToQuery(config.modResults);
    return config;
  });
}

async function writeResXml(root: string) {
  const dir = "android/app/src/main/res/xml";
  fs.ensureDir(dir); // ensures that the directory exists
  // <?xml version="1.0" encoding="utf-8"?>
  // <paths xmlns:android="http://schemas.android.com/apk/res/android">
  //   <files-path name="files" path="." />
  //   <external-files-path name="external_files" path="." />
  //   <external-path name="external_files" path="." />
  //   <cache-path name="cached_files" path="." />
  //   <external-cache-path name="cached_files" path="." />
  //   <root-path name="root" path="." />
  // </paths>
  const xmlObj = {
    paths: {
      $: {
        "xmlns:android": "http://schemas.android.com/apk/res/android",
      },
      "files-path": {
        $: {
          name: "files",
          path: ".",
        },
      },
      "external-files-path": {
        $: {
          name: "external_files",
          path: ".",
        },
      },
      "external-path": {
        $: {
          name: "external_files",
          path: ".",
        },
      },
      "cache-path": {
        $: {
          name: "cached_files",
          path: ".",
        },
      },
      "external-cache-path": {
        $: {
          name: "cached_files",
          path: ".",
        },
      },
      "root-path": {
        $: {
          name: "root",
          path: ".",
        },
      },
    },
  };

  // this will rewrite the file if it exists. // TODO: fix this.
  await XML.writeXMLAsync({ path: `${dir}/file_paths.xml`, xml: xmlObj });
}
function withWrittenResXml(config: ExpoConfig) {
  return withDangerousMod(config, [
    "android",
    async (config) => {
      await writeResXml(config.modRequest.projectRoot);
      return config;
    },
  ]);
}

const withSnapchatSdk: ConfigPlugin = (config) => {
  return withWrittenResXml(
    withPackage(withProvider(withCustomMetaData(withSnapkitGradle(config))))
  );
};

export default createRunOncePlugin(withSnapchatSdk, pkg.name, pkg.version);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants