15

I'm having a lot of trouble with serving a apple-app-site-association file in ReactJS project.

I've searched a lot of GitHub issues pages (for ReactJS, Gatsby, and Angular), forums, and a lot of online communities, and it seems that I can't find a solution for this.


What I've tried is:

  • Adding the file into public/.well-known folder.
  • Adding a separate route via react-router on path "/apple-app-site-association" and returning an tag with file
  • Adding <link rel="apple-app-site-association" href="%PUBLIC_URL%/.well-known/apple-app-site-association"> into public/index.html

Testing through the "aasa-validator" returns:

Your file's 'content-type' header was not found or was not recognized.


Keep in mind that:

  • The apple-app-site-association JSON file must not have a .json file extension.
  • It has to be on "/apple-app-site-association" or "./well-known/apple-app-site-association" links on the website.
  • I can't use a redirect to another page/link.

Thanks in advance!

Ps. If it helps, I'm using a Heroku for deployment.

milut.in
  • 300
  • 1
  • 3
  • 9

10 Answers10

4

For NextJs

As discussed here, it is possible to server apple-app-site-association from NextJs.

Next.js uses the extension to automatically detect the content-type of the file. Since the file is extensionless, it's served as binary content—this should be compatible with Apple's verification.

If Apple requires specific headers, you can overwrite this type:

// next.config.js
module.exports = {
  experimental: {
    headers() {
      return [
        {
          source: "/.well-known/apple-app-site-association",
          headers: [{ key: "content-type", value: "application/json" }]
        }
      ];
    }
  }
};
Ponleu
  • 1,492
  • 12
  • 27
  • 2
    Be careful reader, when I asked this question I had plain Client Side Rendering in mind. NextJS uses Server Side Rendering. You can't convert already existing CSR ReactJS project into NextJS that easily. :) – milut.in Oct 06 '22 at 14:48
2

You can serve the file using React Router. Put this in your index.js or App.js:

const reload = () => window.location.reload();
<Route path="/apple-app-site-association" onEnter={reload} />

More details here: https://brainbank.cc/jamie/lessons/programming-react/serve-static-file-txt-html-via-react-router

2

We serve our CRA app using the npm serve CLI package. This is what we did to resolve the issue of serving our extension-less apple-app-site-association file.

The fix for this is to create the apple-app-site-association as apple-app-site-association.json inside your public/.well-known directory and then create a rewrite rule inside of a file in your public directory called serve.json. The contents of that file should look like this.

{
  "rewrites": [
    {
      "source": "!.well-known/**",
      "destination": "index.html"
    },
    {
      "source": ".well-known/apple-app-site-association",
      "destination": ".well-known/apple-app-site-association.json"
    }
  ]
}

Then when you start your static file server, you don't use the -s or --single argument. You start it using the following command.

serve -c serve.json

The first item will send all requests that don't exist inside of .well-known to index.html, and the second rewrite will send requests for that specific URL to the apple-app-site-association.json file and assign a content-type: application/json header to it. All other files with file extensions should be served as normal, ignoring any rewrite rules.

Dylan Vester
  • 2,686
  • 4
  • 29
  • 40
  • This looks like a solid solution. If anyone tries it, let me know. I will mark this as an accepted answer if it works :) – milut.in Dec 30 '22 at 14:01
  • We have been using this in production for a while now and it works perfectly with serve, apple-app-site-association, and our SPA. – Dylan Vester Jul 02 '23 at 17:05
1

several days have passed and I didn't find an answer or solution. (And I really hate to see an unanswered stackoverflow question when I'm searching for a solution)

I've talked to a lot of people and pretty much everyone said this is impossible. Reason for that is that ReactJS is unable to return JSON type of response upon client sending a GET request.

So we transfered the file onto the back-end side which is working perfectly.

tl;dr It's not possible.

milut.in
  • 300
  • 1
  • 3
  • 9
1

For CRA: The file apple-app-site-association should be added to the public folder or public/.well-known folder. This alone won't make it work. Because it is served with a content-type of application/octet-stream. To fix it, we should use a solution provided by the hosting provider.

For Firebase: I am using Firebase for hosting my CRA app. So, for firebase, it is possible to specify the response headers for the path. The following gist shows how to do this. Make sure that the appAssociation should also be set to prevent firebase dynamic links from serving some other AASA file.

firebase.json config

{
  "hosting": {
    "public": "public",
    "headers": [
      {
        "source": "/.well-known/apple-app-site-association",
        "headers": [
          {
            "key": "Content-Type",
            "value": "application/json"
          }
        ]
      }
    ],
    "appAssociation": "NONE"
  }
}
vijayst
  • 20,359
  • 18
  • 69
  • 113
1

If you're using Cloudfront in AWS you can create a custom Response Headers Policy:

enter image description here

enter image description here

Andrew
  • 3,545
  • 4
  • 31
  • 37
1

If you have any other redirects / rewrite rules make sure the apple-app-site-association re-write is placed before others.

For example this is with AWS Amplify for React JS:

[
    {
        "source": "/.well-known/apple-app-site-association",
        "target": "/.well-known/apple-app-site-association.json",
        "status": "200",
        "condition": null
    },
    {
        "source": "</^[^.]+$|\\.(?!(css|gif|ico|jpg|js|png|txt|svg|woff|ttf|map|json)$)([^.]+$)/>",
        "target": "/index.html",
        "status": "200",
        "condition": null
    }
]

with the apple-app-site-association file placed as a JSON file here:

/public/.well-known/apple-app-site-association.json

Dylan w
  • 2,565
  • 1
  • 18
  • 30
0

Disclaimer: This is only applicable if you have an Nginx implementation.

I got stuck on this and couldn't figure out a way to add the apple site association file to the react code in any way. However, I was able to solve the issue by looking outside the react box and inside my server configuration box i.e. Nginx.

Here are the steps:

  1. In the server store the AASA or apple-app-site-association.json file in a particular location - I chose to store it at (had to create two certifications and ios directories)

/var/www/certificates/ios/

  1. Now go to the sites-available folder

cd /etc/nginx/sites-available/

  1. Here, you will find the file with your web app's Nginx configuration information. Let's say, the name of my file was example-web-app, so open the file using vim with sudo privileges:

sudo vim mayank-web-app

  1. Now inside this file, you need to find

location / {

  1. Just above this line paste this code block
location /apple-app-site-association {
        alias /var/www/certificates/ios/;
        index apple-app-site-association.json
        autoindex on; }
  1. Now save the file and exit, by pressing esc and typing

wq!

  1. Now check if the changes are valid by typing

sudo nginx -t

You should get this as output

nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
  1. After this you will have to go to the sites-enabled directory

cd ../sites-enabled 9. Update the symlink here sudo ln -s /etc/nginx/sites-available/example-web-app .

  1. Now reload the nginx service

sudo service nginx reload

  1. Now you can check this with two methods:

a. https://branch.io/resources/aasa-validator/#resultsbox.
b. https://example.com/apple-app-site-association

0

I has this problem using react/redux and Next.js this is how I solved the issue

in my /static folder I put my apple-app-site-association

    {
  "webcredentials": {
        "apps": ["12345431.com.app"]
    },
  "applinks": {
      "apps": [],
      "details": [
          {
              "appID": "12345431.com.app",
              "paths": [ "*"]
          }
        }
      ]
  }
}

I created a component called Apple AppleAssociation.jsx in that file I have

import React from 'react'

function AppleAssociation() {
  return (
    //path to apple app site association file
    <>
       <link rel="apple-app-site-association file" href="/static/apple-app-site-association" />
     </>
  )
}

export default AppleAssociation

and in my _app.jsx file I import that into my head

import React from 'react'
import Head from 'next/head'
import withRedux from 'next-redux-wrapper'
import App, { Container as NextContainer } from 'next/app'
import { Provider as ReduxProvider } from 'react-redux'
import {
  AppleAssociation,
} from '../components/head'
import makeStore from '../lib/store'


class CustomApp extends App {
  static async getInitialProps({ Component}) {
    let pageProps = {}


    return {
      pageProps,
    }
  }

  componentDidMount() {
  }

  render() {
    const { Component, pageProps, session, store } = this.props

    return (
      <NextContainer>
        <Head>
          <meta
            name="viewport"
            content="width=device-width, initial-scale=1, minimal-ui"
          />
          <AppleAssociation />
        </Head>

        <ReduxProvider store={store}>
 
            <NextSeo config={seo} />
            <Component {...pageProps} />

        </ReduxProvider>
      </NextContainer>
    )
  }
}

export default withRedux(makeStore)(CustomApp)

you can test this by using https://branch.io/resources/aasa-validator/#resultsbox

0

I've had a hard time figuring this out for the last two weeks, but I've made it. My next.js version: "next": "12.1.1". In the public folder, I created a .well-known folder and added the apple-app-site-association file there with the following configuration:

{
  "applinks": {
    "apps": [],
    "details": [
      {
        "appID": "xyz",
        "paths": [
          "/*"
        ]
      }
    ]
  }
}

There were two problems. First:

  • When running the production version on jenkins using dockerfile, for unknown reasons, there was no public folder in the files. You can verify this very simply by entering one of the icons in the public address into the website address. For example in my case: https://www.pageaddress.com/android-icon-36x36.png If it displays, public works fine, if not, it's either in the wrong place or it's not there at all. If it is not there, you need to add it to the build in the dockerfile. My dockerfile:

FROM node:16.16-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN npm install

FROM node:16.16-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

FROM node:16.16-alpine AS runner
WORKDIR /app

ENV NEXT_TELEMETRY_DISABLED 1

COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

#add public folder
COPY --from=builder /app/public/ ./public

ENV PORT 3000

CMD ["npm", "start"]

The second problem was that one of the certificates was missing or one of the certificates was bad. At first glance, everything was fine on the website, but after checking the server, it turned out that there was a problem. Brancho.io will not show it to you, it showed me "A request to this domain failed". Only here: https://yurl.chayev.com/ I got information that something is wrong with the certificate, so the topic has been checked and now it has passed on branch.io and everything is green.

Ps. If anything, don't worry about the fact that after entering: https://www.pageaddress.com/.well-known/apple-app-site-association you will not see a file in .json format, only a file without extension will be downloaded. It does not matter. At first I thought that this could be one of the problems and I lost some time on it and finally the file is not displayed as .json like here, for example: https://www.google.com/apple-app-site-association and everything works fine. I hope this helps someone. I created an account to share this information because I was struggling with it for a long time, I checked many forums, many ways and all for nothing.

ttn
  • 1