Home | History | Annotate | Download | only in app-links
      1 page.title=Handling App Links
      2 page.image=images/cards/card-app-linking_2x.png
      3 page.keywords=applinking, deeplinks, intents
      4 page.tags=androidm,marshmallow
      5 @jd:body
      6 
      7 <div id="tb-wrapper">
      8   <div id="tb">
      9     <h2>This lesson teaches you to</h2>
     10     <ol>
     11         <li><a href="#url-handling">Understand URI Request Handling</a> </li>
     12         <li><a href="#intent-handler">Create an Intent Handler for URIs</a></li>
     13         <li><a href="#request-verify">Request App Links Verification</a></li>
     14         <li><a href="#web-assoc">Declare Website Associations</a></li>
     15         <li><a href="#testing">Test App Links</a></li>
     16     </ol>
     17   <h2>See also</h2>
     18   <ol>
     19     <li><a href="{@docRoot}tools/help/app-link-indexing.html">Supporting URLs and App Indexing in Android Studio</a></li>
     20   </ol>
     21   </div>
     22 </div>
     23 
     24 
     25 
     26 <p>
     27   Users following web links on devices are frequently presented with confusing choices. Tapping a
     28   link often results in the system asking the user which app should handle that link. For example,
     29   clicking a URI in an email from a bank might result in a dialog asking the user whether to use
     30   the browser, or the bank's own app, to open the link. Android 6.0 (API level 23) and higher allow
     31   an app to designate itself as the default handler of a given type of link. If the user doesn't
     32   want the app to be the default handler, they can override this behavior from
     33   <strong>Settings</strong>.
     34 </p>
     35 
     36 <p>
     37   Automatic handling of links requires the cooperation of app developers and website owners.
     38   A developer must configure their app to declare associations with one or more websites, and to
     39   request that the system verify those associations. A website owner must, in turn, provide
     40   that verification by publishing a <a href="http://developers.google.com/digital-asset-links/"><i>Digital
     41   Asset Links</i></a> file. The general steps for creating verified app links are as follows:
     42 </p>
     43 
     44 <ol>
     45   <li>In your app manifest, create intent filters for your website URIs.</li>
     46   <li>Configure your app to request verification of app links.</li>
     47   <li>Publish a Digital Asset Links JSON file on your websites to provide verification.</li>
     48 </ol>
     49 
     50 <h2 id="url-handling">Understand URI Request Handling</h2>
     51 
     52 <p>
     53   The app links feature allows your app to become the default handler for the website URIs you
     54   specify, as long as the user has not already chosen a default app to handle that URI pattern.
     55   When a clicked link or programmatic request invokes a web URI intent, the Android system
     56   uses the following criteria, in descending order, to determine how to handle the request:
     57 </p>
     58 
     59 <ol>
     60   <li>
     61     <strong>The user has set app link associations</strong>: If the user has designated an app to
     62     handle app links, the system passes the web URI request to that app. A user can set this
     63     association in one of two ways: clicking <strong>Always</strong> when selecting an app
     64     from an app-selection dialog; or, opening <em>Settings &gt; Apps &gt; (gear icon)
     65     &gt; App links</em>, selecting an app to use, and setting the app's
     66     <strong>App links</strong> property to the <strong>Open in this app</strong> option.
     67   </li>
     68 
     69   <li>
     70     <strong>The user has set no association, and there is one supporting app</strong>: If the user
     71     has not set a preference that matches the web URI request, and there is only one app declaring
     72     support for the intents URI pattern, the system automatically passes the request to that app.
     73   </li>
     74 
     75   <li>
     76     <strong>The user has set no association, and there are multiple supporting apps</strong>: If
     77     there are multiple apps declaring support for the web URI pattern, the system displays an
     78     app-selection dialog, prompting the user to select the most appropriate app.
     79   </li>
     80 </ol>
     81 
     82 <p>
     83   In case 2, if the user has newly installed the app, and the system has
     84   verified it as a handler for this type of link, the system sets the app as the default handler. In
     85   the other two cases, the presence of a verified app link handler has no effect on system behavior.
     86 </p>
     87 
     88 
     89 <h2 id="intent-handler">Create an Intent Handler for URIs</h2>
     90 
     91 <p>
     92   App links are based on the <a href="{@docRoot}guide/components/intents-filters.html">Intent</a>
     93   framework, which enables apps to handle requests from the system or other apps. Multiple apps may
     94   declare the same web link URI patterns in their intent filters. When a user clicks on a web link
     95   that does not have a default launch handler, the platform selects an app to handle the request,
     96   using the criteria described in <a href="#url-handling">Understanding URI Request Handling</a>.
     97 </p>
     98 
     99 <p>
    100   To enable your app to handle links, use intent filters in your app manifest to declare the URI
    101   patterns that your app handles. The following example shows an intent filter that can
    102   handle links to {@code http://www.android.com} and {@code https://www.android.com}:
    103 </p>
    104 
    105 <pre>
    106 &lt;activity ...&gt;
    107     &lt;intent-filter&gt;
    108         &lt;action android:name="android.intent.action.VIEW" /&gt;
    109         &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    110         &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    111         &lt;data android:scheme="http" /&gt;
    112         &lt;data android:scheme="https" /&gt;
    113         &lt;data android:host="www.android.com" /&gt;
    114     &lt;/intent-filter&gt;
    115 &lt;/activity&gt;
    116 </pre>
    117 
    118 <p>
    119   As this example shows, intent filters for app links must declare an {@code android:scheme}
    120   value of {@code http}, {@code https}, or both. The filter must not declare
    121   any other schemes. The filter must also include the {@code android.intent.action.VIEW} and
    122   {@code android.intent.category.BROWSABLE} category names.
    123 </p>
    124 
    125 <p>
    126   This manifest declaration defines the connection between your app and a website. However, in
    127   order to have the system treat your app as the default handler for a set of URIs, you must
    128   also request that the system verify this connection.
    129   The next section explains how to implement this verification.
    130 </p>
    131 
    132 
    133 <h2 id="request-verify">Request App Links Verification</h2>
    134 
    135 <p>
    136   In addition to using intent filters to declare an association between your app and a website,
    137   your manifest must also include an additional declaration for requesting automatic verification.
    138   When this declaration is present, the Android system attempts to verify your app after
    139   installation. If the verification succeeds, and the user has not set an alternate
    140   preference for handling your website URIs, the system automatically routes those URI requests to
    141   your app.
    142 </p>
    143 
    144 <p>
    145   The system performs app-link verifications by comparing the host names in the data elements of
    146   the apps intent filters against the Digital Asset Links files ({@code assetlinks.json}) hosted
    147   on the respective web domains. To enable the system to verify a host, make sure that your intent
    148   filter declarations include the {@code android.intent.action.VIEW} intent action and {@code
    149   android.intent.category.BROWSABLE} intent category.
    150 </p>
    151 
    152 
    153 <h3 id="config-verify">Enabling automatic verification</h3>
    154 
    155 <p>
    156   To enable link handling verification for your app, set the {@code android:autoVerify} attribute to
    157   {@code true} on at least one of the web URI intent filters in your app manifest, as shown in the
    158   following manifest code snippet:
    159 </p>
    160 
    161 <pre>
    162 &lt;activity ...&gt;
    163 
    164     &lt;intent-filter <strong>android:autoVerify="true"</strong>&gt;
    165         &lt;action android:name="android.intent.action.VIEW" /&gt;
    166         &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    167         &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    168         &lt;data android:scheme="http" android:host="www.android.com" /&gt;
    169         &lt;data android:scheme="https" android:host="www.android.com" /&gt;
    170     &lt;/intent-filter&gt;
    171 
    172 &lt;/activity&gt;
    173 </pre>
    174 
    175 <p>
    176   When the {@code android:autoVerify} attribute is present, installing your app causes the system
    177   to attempt to verify all hosts associated with the web URIs in all of your app's intent filters.
    178   The system treats your app as the default handler for the specified URI pattern only if it
    179   successfully verifies <em>all</em> app link patterns declared in your manifest.
    180 </p>
    181 
    182 
    183 <h3 id="multi-host">Supporting app linking for multiple hosts</h3>
    184 
    185 <p>
    186   The system must be able to verify every host specified in the apps web URI intent filters data
    187   elements against the Digital Asset Links files hosted on the respective web domains. If any
    188   verification fails, the app is not verified to be a default handler for any of the web URI
    189   patterns defined in the app's intent filters. For example, an app with the following intent
    190   filters would fail verification if an {@code assetlinks.json} file were not found at both
    191   {@code https://www.domain1.com/.well-known/assetlinks.json} and
    192   {@code https://www.domain2.com/.well-known/assetlinks.json}:
    193 </p>
    194 
    195 <pre>
    196 &lt;application&gt;
    197 
    198   &lt;activity android:name=MainActivity&gt;
    199     &lt;intent-filter <strong>android:autoVerify="true"</strong>&gt;
    200       &lt;action android:name="android.intent.action.VIEW" /&gt;
    201       &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    202       &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    203       &lt;data android:scheme="http" android:host="www.domain1.com" /&gt;
    204       &lt;data android:scheme="https" android:host="www.domain1.com" /&gt;
    205     &lt;/intent-filter&gt;
    206   &lt;/activity&gt;
    207   &lt;activity android:name=SecondActivity&gt;
    208     &lt;intent-filter&gt;
    209       &lt;action android:name="android.intent.action.VIEW" /&gt;
    210       &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    211       &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    212       &lt;data android:scheme="https" android:host="www.domain2.com" /&gt;
    213     &lt;/intent-filter&gt;
    214   &lt;/activity&gt;
    215 
    216 &lt;/application
    217 </pre>
    218 
    219 
    220 <h3 id="multi-subdomain">Supporting app linking for multiple subdomains</h3>
    221 
    222 <p>
    223   The Digital Asset Links protocol treats subdomains as unique, separate hosts. If your intent
    224   filter lists both the {@code www.example.com} and {@code mobile.example.com} subdomains as
    225   hosts, you must host a separate {@code assetlink.json} file on each subdomain. For example, an
    226   app with the following intent filter declaration would pass verification only if the website
    227   owner published valid {@code assetlinks.json} files at both
    228   {@code https://www.example.com/.well-known/assetlinks.json} and
    229   {@code https://mobile.example.com/.well-known/assetlinks.json}:
    230 </p>
    231 
    232 <pre>
    233 &lt;application&gt;
    234   &lt;activity android:name=MainActivity&gt;
    235     &lt;intent-filter <strong>android:autoVerify="true"</strong>&gt;
    236       &lt;action android:name="android.intent.action.VIEW" /&gt;
    237       &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    238       &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    239       &lt;data android:scheme="http" android:host="www.example.com" /&gt;
    240       &lt;data android:scheme="https" android:host="mobile.example.com" /&gt;
    241     &lt;/intent-filter&gt;
    242   &lt;/activity&gt;
    243 &lt;/application&gt;
    244 </pre>
    245 
    246 
    247 <h2 id="web-assoc">Declare Website Associations</h2>
    248 
    249 <p>
    250   For app link verification to be successful, website owners must declare associations
    251   with apps. A site owner declares the relationship to an app by hosting a Digital Asset Links JSON
    252   file, with the name {@code assetlinks.json}, at the following well-known location on the domain:
    253 </p>
    254 
    255 <pre>
    256 https://<em>domain</em>[:<em>optional_port</em>]/.well-known/assetlinks.json
    257 </pre>
    258 
    259 <p class="note">
    260   <strong>Important:</strong> The system verifies the JSON file via the encrypted HTTPS protocol.
    261   Make sure that your hosted file is accessible over an HTTPS connection, regardless of whether
    262   your app's intent filter includes {@code https}.
    263 </p>
    264 
    265 <p>
    266   A Digital Asset Links JSON file indicates the Android apps that are associated with the website.
    267   The JSON file uses the following fields to identify associated apps:
    268 </p>
    269 
    270 <ul>
    271   <li>{@code package_name}: The package name declared in the app's manifest.</li>
    272 
    273   <li>{@code sha256_cert_fingerprints}: The SHA256 fingerprints of your apps signing certificate.
    274     You can use the following command to generate the fingerprint via the Java keytool:
    275 
    276     <pre class="no-pretty-print">
    277 $ keytool -list -v -keystore my-release-key.keystore
    278     </pre>
    279 
    280     This field supports multiple fingerprints, which can be used to support different versions
    281     of your app, such as debug and production builds.
    282   </li>
    283 </ul>
    284 
    285 <p>
    286   The following example {@code assetlinks.json} file grants link-opening rights to a
    287   {@code com.example} Android app:
    288 </p>
    289 
    290 <pre>
    291 [{
    292   "relation": ["delegate_permission/common.handle_all_urls"],
    293   "target": {
    294     "namespace": "android_app",
    295     "package_name": "com.example",
    296     "sha256_cert_fingerprints":
    297     ["14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5"]
    298   }
    299 }]
    300 </pre>
    301 
    302 
    303 <h3 id="multiple-apps">Associating a website with multiple apps</h3>
    304 
    305 <p>
    306   A website can declare associations with multiple apps within the same {@code assetlinks.json}
    307   file. The following file listing shows an example of a statement file that declares association
    308   with two apps, separately, and resides at
    309   <code>https://www.example.com/.well-known/assetlinks.json</code>:
    310 </p>
    311 
    312 <pre>
    313 [{
    314   "relation": ["delegate_permission/common.handle_all_urls"],
    315   "target": {
    316     "namespace": "android_app",
    317     "package_name": <strong>"example.com.puppies.app"</strong>,
    318     "sha256_cert_fingerprints":
    319     ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
    320   }
    321   },
    322   {
    323   "relation": ["delegate_permission/common.handle_all_urls"],
    324   "target": {
    325     "namespace": "android_app",
    326     "package_name": "<strong>example.com.monkeys.app</strong>",
    327     "sha256_cert_fingerprints":
    328     ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
    329   }
    330 }]
    331 </pre>
    332 
    333 <p>
    334   Different apps may handle links for different resources under the same web host. For example,
    335   app1 may declare an intent filter for {@code https://example.com/articles}, and app2 may declare
    336   an intent filter for {@code https://example.com/videos}.
    337 </p>
    338 
    339 <p class="note">
    340   <strong>Note:</strong> Multiple apps associated with a domain may be signed with the same or
    341   different certificates.
    342 </p>
    343 
    344 
    345 <h3 id="multi-site">Associating multiple websites with a single app</h3>
    346 
    347 <p>
    348   Multiple websites can declare associations with the same app in their respective {@code
    349   assetlinks.json} files. The following file listings show an example of how to declare the
    350   association of domain1 and domain2 with app1. The first listing shows the association of
    351   domain1 with app1:
    352 </p>
    353 
    354 <pre>
    355 https://www.domain1.com/.well-known/assetlinks.json
    356 
    357 [{
    358   "relation": ["delegate_permission/common.handle_all_urls"],
    359   "target": {
    360     "namespace": "android_app",
    361     "package_name": "<strong>com.mycompany.app1</strong>",
    362     "sha256_cert_fingerprints":
    363     ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
    364   }
    365 }]
    366 </pre>
    367 
    368 <p>The next listing shows the association of domain2 with app1. Only the very last line, which
    369 specifies the URL, is different:</p>
    370 
    371 <pre>
    372 https://www.domain2.com/.well-known/assetlinks.json
    373 
    374 [{
    375   "relation": ["delegate_permission/common.handle_all_urls"],
    376   "target": {
    377     "namespace": "android_app",
    378     "package_name": "<strong>com.mycompany.app1</strong>",
    379     "sha256_cert_fingerprints":
    380     ["<strong>14:6D:E9:83:C5:73:06:50:D8:EE:B9:95:2F:34:FC:64:16:A0:83:42:E6:1D:BE:A8:8A:04:96:B2:3F:CF:44:E5</strong>"]
    381   }
    382 }]
    383 </pre>
    384 
    385 <h2 id="testing">Test App Links</h2>
    386 
    387 <p>
    388   When implementing the app linking feature, you should test the linking functionality to
    389   make sure the system can associate your app with your websites, and handle URI requests,
    390   as you expect.
    391 </p>
    392 
    393 
    394 <h3 id="test-hosts">Confirm the list of hosts to verify</h3>
    395 
    396 <p>
    397   When testing, you should confirm the list of associated hosts that the system should verify
    398   for your app. Make a list of all web URIs whose corresponding intent filters include the following
    399   attributes and elements:
    400 </p>
    401 
    402 <ul>
    403   <li>{@code android:scheme} attribute with a value of {@code http} or {@code https}
    404   </li>
    405   <li>{@code android:host} attribute with a domain URI pattern
    406   </li>
    407   <li>{@code android.intent.action.VIEW} category element
    408   </li>
    409   <li>{@code android.intent.category.BROWSABLE} category element
    410   </li>
    411 </ul>
    412 
    413 <p>
    414   Use this list to check that a Digital Asset Links JSON file is provided on each named host
    415   and subdomain.
    416 </p>
    417 
    418 
    419 <h3 id="test-dal-files">Confirm the Digital Asset Links files</h3>
    420 
    421 <p>
    422   For each website, use the Digital Asset Links API to confirm that the Digital Asset Links JSON
    423   file is properly hosted and defined:
    424 </p>
    425 
    426 <pre>
    427 https://digitalassetlinks.googleapis.com/v1/statements:list?
    428    source.web.site=https://<strong>&lt;domain1&gt;:&lt;port&gt;</strong>&amp;
    429    relation=delegate_permission/common.handle_all_urls
    430 </pre>
    431 
    432 
    433 <h3 id="test-intent">Testing a web URI intent</h3>
    434 
    435 <p>
    436   Once you have confirmed the list of websites to associate with your app, and you have confirmed
    437   that the hosted JSON file is valid, install the app on your device. Wait at least 20 seconds for
    438   the asynchronous verification process to complete. Use the following command to check
    439   whether the system verified your app and set the correct link handling policies:
    440 </p>
    441 
    442 <pre>
    443 adb shell am start -a android.intent.action.VIEW \
    444     -c android.intent.category.BROWSABLE \
    445     -d "http://<domain1>:<port>;"
    446 </pre>
    447 
    448 
    449 <h3 id="check-link-policies">Check link policies</h3>
    450 
    451 <p>
    452   As part of your testing process, you can check the current system settings for link handling.
    453   Use the following command to get a listing of existing link-handling policies for all
    454   applications:
    455 </p>
    456 
    457 <pre>
    458 adb shell dumpsys package domain-preferred-apps
    459  --or--
    460 adb shell dumpsys package d
    461 </pre>
    462 
    463 <p class="note">
    464   <strong>Note:</strong> Make sure you wait at least 20 seconds after installation of your app to
    465   allow for the system to complete the verification process.
    466 </p>
    467 
    468 <p>
    469   The command returns a listing of each user or profile defined on the device,
    470   preceded by a header in the following format:
    471 </p>
    472 
    473 <pre>
    474 App linkages for user 0:
    475 </pre>
    476 
    477 <p>
    478   Following this header, the output uses the following format to list the link-handling settings
    479   for that user:
    480 </p>
    481 
    482 <pre>
    483 Package: com.android.vending
    484 Domains: play.google.com market.android.com
    485 Status: always : 200000002
    486 </pre>
    487 
    488 <p>This listing indicates which apps are associated with which domains for that user:</p>
    489 
    490 <ul>
    491   <li>{@code Package} - Identifies an app by its package name, as declared in its manifest.
    492   </li>
    493   <li>{@code Domains} - Shows the full list of hosts whose web links this app handles, using
    494   blank spaces as delimiters.
    495   </li>
    496   <li>{@code Status} - Shows the current link-handling setting for this app. An app that has
    497   passed verification, and whose manifest contains {@code android:autoVerify="true"}, shows a status
    498   of {@code always}. The hexadecimal number after this status is related to the Android system's
    499   record of the users app linkage preferences. This value does not indicate whether verification
    500   succeeded.
    501   </li>
    502 </ul>
    503 
    504 <p class="note">
    505   <strong>Note:</strong> If a user changes the app link settings for an app before verification
    506   is complete, you may see a false positive for a successful verification, even though
    507   verification has failed. This verification failure, however, does not matter if the user
    508   explicitly enabled the app to open supported links without asking. This is because
    509   user preferences take precedence over programmatic verification (or lack of it). As a result,
    510   the link goes directly to your app, without showing a dialog, just as if verification had
    511   succeeded.
    512 </p>
    513 
    514 
    515 
    516 <h3 id="test-example">Test example</h3>
    517 
    518 <p>
    519   For app link verification to succeed, the system must be able to verify your app with all of
    520   the websites that you specify in your apps intent filters, and that meet the criteria for app
    521   links. The following example shows a manifest configuration with several app links defined:
    522 </p>
    523 
    524 <pre>
    525 &lt;application&gt;
    526 
    527     &lt;activity android:name=MainActivity&gt;
    528         &lt;intent-filter <strong>android:autoVerify="true"</strong>&gt;
    529             &lt;action android:name="android.intent.action.VIEW" /&gt;
    530             &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    531             &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    532             &lt;data android:scheme="http" android:host="www.example.com" /&gt;
    533             &lt;data android:scheme="https" android:host="mobile.example.com" /&gt;
    534         &lt;/intent-filter&gt;
    535         &lt;intent-filter&gt;
    536             &lt;action android:name="android.intent.action.VIEW" /&gt;
    537             &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    538             &lt;data android:scheme="http" android:host="www.example2.com" /&gt;
    539         &lt;/intent-filter&gt;
    540     &lt;/activity&gt;
    541 
    542     &lt;activity android:name=SecondActivity&gt;
    543         &lt;intent-filter&gt;
    544             &lt;action android:name="android.intent.action.VIEW" /&gt;
    545             &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    546             &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    547             &lt;data android:scheme="http" android:host="account.example.com" /&gt;
    548         &lt;/intent-filter&gt;
    549     &lt;/activity&gt;
    550 
    551       &lt;activity android:name=ThirdActivity&gt;
    552         &lt;intent-filter&gt;
    553             &lt;action android:name="android.intent.action.VIEW" /&gt;
    554             &lt;category android:name="android.intent.category.DEFAULT" /&gt;
    555             &lt;data android:scheme="http" android:host="map.example.com" /&gt;
    556         &lt;/intent-filter&gt;
    557         &lt;intent-filter&gt;
    558             &lt;action android:name="android.intent.action.VIEW" /&gt;
    559             &lt;category android:name="android.intent.category.BROWSABLE" /&gt;
    560             &lt;data android:scheme="market" android:host="example.com" /&gt;
    561         &lt;/intent-filter&gt;
    562       &lt;/activity&gt;
    563 
    564 &lt;/application&gt;
    565 </pre>
    566 
    567 <p>
    568   The list of hosts that the platform would attempt to verify from the above manifest is:
    569 </p>
    570 
    571 <pre>
    572 www.example.com
    573 mobile.example.com
    574 www.example2.com
    575 account.example.com
    576 </pre>
    577 
    578 <p>
    579   The list of hosts that the platform would not attempt to verify from the above manifest is:
    580 </p>
    581 
    582 <pre>
    583 map.example.com (it does not have android.intent.category.BROWSABLE)
    584 market://example.com (it does not have either an http or https scheme)
    585 </pre>
    586