tschoffelen / react-native-map-link

🗺 Open the map app of the user's choice.
MIT License
648 stars 137 forks source link

Update document of Post-install steps for expo user #212

Closed qaws5503 closed 1 year ago

qaws5503 commented 2 years ago

I dig in with the problem here #209 . After plenty of hours, I finally work through it. As the author mention in Post-install steps Android must update AndroidManifest.xml. But in the Expo section it only says how it works on iOS, doesn't mention how to work on android while using Expo.

So I searched how to change AndroidManifest.xml file in Expo. And the answer is using plugins, but this only work on Expo SDK 41 or greater, please check for the SDK first.

So follow the steps below:

  1. create a file called withAndroidPackageVisibile.js, and paste this to the file. This will write the same AndroidManifest.xml mention in Post-install steps Android steps.
    
    const { withAndroidManifest } = require("@expo/config-plugins");

module.exports = function androidManifestPlugin(config) { return withAndroidManifest(config, async (config) => { let androidManifest = config.modResults.manifest; androidManifest["queries"] = [ ...androidManifest["queries"], packageVisibilityList, ]; return config; }); }; const packageVisibilityList = { intent: [ { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "geo", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "google.navigation", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "applemaps", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "citymapper", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "uber", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "lyft", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "transit", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "truckmap", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "waze", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "yandexnavi", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "moovit", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "yandexmaps://maps.yandex.", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "yandextaxi", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "kakaomap", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "mapycz", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "mapsme", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "osmand.geo", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "gett", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "nmap", }, }, }, { action: { $: { "android:name": "android.intent.action.VIEW", }, }, data: { $: { "android:scheme": "dgis", }, }, }, ], };

2. Then switch to `app.json` and change the following

{ "expo": { ... "plugins": [ ... , "./the/path/to/withAndroidPackageVisibile.js" ] } }


3. Finally re-build the app, I only test on `eas build`. I can't assure there is no problem with `expo build`.

You can learn more about how to use plugins in [here](https://chafikgharbi.com/expo-android-manifest/).
Happy coding guys!
emehmet commented 2 years ago

Hi, It still won't open for me. Are there any permission that need to be added?

qaws5503 commented 2 years ago

Hi, It still won't open for me. Are there any permission that need to be added?

@emehmet I didn't add any extra permission, so I recommend you to check if AndroidManifest.xml has correctly been changed. You can check it by below.

You can first type expo eject in the command line. Then find AndroidManifest.xml under android folder and check for if the permission is like this. By doing this you can check if withAndroidPackageVisibile.js works like what you want.

chunhungchen commented 2 years ago

I dig in with the problem here #209 . After plenty of hours, I finally work through it. As the author mention in Post-install steps Android must update AndroidManifest.xml. But in the Expo section it only says how it works on iOS, doesn't mention how to work on android while using Expo.

So I searched how to change AndroidManifest.xml file in Expo. And the answer is using plugins, but this only work on Expo SDK 41 or greater, please check for the SDK first.

So follow the steps below:

  1. create a file called withAndroidPackageVisibile.js, and paste this to the file. This will write the same AndroidManifest.xml mention in Post-install steps Android steps.

const { withAndroidManifest } = require("@expo/config-plugins");

module.exports = function androidManifestPlugin(config) {
  return withAndroidManifest(config, async (config) => {
    let androidManifest = config.modResults.manifest;
    androidManifest["queries"] = [
      ...androidManifest["queries"],
      packageVisibilityList,
    ];
    return config;
  });
};

thanks for your solution but it seems should modify it a little bit here.

module.exports = function androidManifestPlugin(config) {
   return withAndroidManifest(config, async (config) => {
     let androidManifest = config.modResults.manifest;
     androidManifest["queries"] = [
       ...androidManifest["queries"],
       packageVisibilityList,
     ];

     config.modResults.manifest = androidManifest; // here

     return config;
   });
 };
Buk1m commented 2 years ago

Hi, I tried this solution but it only works for me in Expo Go or with expo eject/'expo prebuild'. While using expo build:android the apk does not contain output of your plugin. I decompiled the apk using apktool and the AndroidManifest does not contain those intents. Did you managed to make it work with expo managed project on standalone build?

I'm using Expo SDK 43 and version "2.9.3" of this library

emehmet commented 2 years ago

It worked for me when I deleted node_modules and build again with eas build on development-client.

Buk1m commented 2 years ago

Thanks, I will have to migrate the project to EAS cli, I will post an update if it is working on EAS build. (it may take few days as it's not a priority for now).

tschoffelen commented 1 year ago

I think this is now resolved, but please do feel free to open a PR if more changes are needed. Thanks everyone!

steveafrost commented 1 year ago

This appears to be right with one issue I keep running across: there are duplicate query keeps in the AndroidManifest.xml after following the post install steps here.

With duplicate query keys, the app is not installable on devices w/ a silent fail.

tschoffelen commented 1 year ago

Do you think this is due to a bug in the Expo plugin? Or is it because of following both the Android instructions + Expo instructions from the README?

steveafrost commented 1 year ago

@tschoffelen thanks for the quick reply. It is due to my misunderstanding of the js -> xml conversion I think. Using the above code in this (old) comment ended up with duplicate query keys which broke installs like I mentioned.

The duplicate query keys were happening when adding map intents to the existing query key as such

androidManifest["queries"] = [
      ...androidManifest["queries"],
      packageVisibilityList,
    ];

I updated that piece to concat the first intent with the intents the app required to open map apps on Android.

const androidManifest = config.modResults.manifest;
const existingIntent = androidManifest.queries[0].intent;

androidManifest.queries[0].intent = existingIntent.concat(mapAppIntents)

The whole plugin file

const supportedApps = [
  "geo",
  "google.navigation",
  "waze",
  "lyft",
  "uber",
  "transit",
];

const mapAppIntents = supportedApps.map((app) => {
  return {
    action: {
      $: { "android:name": "android.intent.action.VIEW" }
    },
    data: {
      $: { "android:scheme": app },
    },
  };
});

module.exports = function androidManifestPlugin(config) {
  return withAndroidManifest(config, async (config) => {
    const androidManifest = config.modResults.manifest;
    const existingIntent = androidManifest.queries[0].intent;

    androidManifest.queries[0].intent = existingIntent.concat(mapAppIntents); <-- modification

    return config;
  });
};
tschoffelen commented 1 year ago

Oh amazing! Would you be able to open a PR to get this change merged in?