Native MP3s not playing in iOS 8 when behind .htaccess - ios

I have been serving some mp3s to a small community for years just by linking straight to the MP3 and letting the device's browser handle the playback. All worked fine until users updated their iPhones to iOS 8. Now playing MP3's natively doesn't work. After lots of testing I seem to have narrowed it down to the use of .htaccess.
Here are two identical directories with the same mp3 and directory listing software in them. But one is password protected (U:music P:access).
Normal: http://danielmee.com/dl/
Secured: http://danielmee.com/dl-secure/
I've also tried using a JS player which also broke once behind the secure directory.
What changed in iOS 8 to disable MP3 playback and is there a way to fix it?

The hoops that iOS goes through to play a music file are interesting, to say the least. Looking at a packet trace, the credentials are sent properly for the initial request of the file, but the subsequent partial requests do not have credentials. This is likely a bug in Safari; if you get a free developer account with Apple, you can report the problem to them.
HTTP authentication works this way: the browser makes a request for a resource; the server responds with "401 Authorization Needed" and includes a WWW-Authenticate header indicating the type of authentication — in your case, basic — and the "realm" which is just a way of grouping protected resources. The client re-requests the same resource, adding an Authorization header that contains the username and password — in the case of basic auth, it's just base 64 user:pass. Typically, the browser will cache these credentials and send them without being asked, for every subsequent request within the same realm.

Related

How do I implement deferred deep linking in an iOS app?

I want to implement deferred deep linking in my iOS app as a means of tracking referrals. When a user of my app wants to refer a friend, I'll generate a URL that has a unique referral code. When the other person receives the link and opens it, I want it to take them to my app's page in the App Store. Then if they install my app, when it first opens, I need a way for it to read the referral code from the original URL.
I've found may pages about deferred deep linking on the web but none that really explain how to do it. Instead, these pages all end up telling you to install some third-party code or use some commercial service. This isn't what I'm after. I want to learn how to do this myself.
There are lots of old pages out there that recommend convoluted and error-prone solutions, like tracking the user's IP address, putting the referral code into the clipboard, or somehow obtaining it from a cookie in a web view. I don't think these are the correct solutions to be using in 2022.
If anyone can recommend the appropriate resource, I'd appreciate it.
If it is the case that Apple simply doesn't want us to do this and doesn't provide any support for it, then I'd like to know that too. I was under the impression that they did, but maybe I'm wrong.
Thanks,
Frank
Apple's Universal Links allow for this (would understand the difference between the typical URL Scheme and Universal Links as threshold). This assumes you're willing to do some lifting server-side along with other hurdles on the iOS side, largely administrative.
A benefit of Universal Links and the server-side work is that you're provided a fallback webpage if a user does not have the app installed. Since the app should open if downloaded, you could typically just redirect to the app store from this URL. In this case, though, before any redirects, you could execute an operation to decode the unique params passed in the URL and persist it in a remote data store. The data encoded needs to be required and verifiably unique during your registration -- email seems ideal.
If that's feasible, your standard registration flow could require email verification with a link to the app as a mandatory entry point (think slack magic link). When the user submits his/her email to verify, you could first check that email against your data store to see if it maps to any previously decoded referrals saved from the flow above. If so, you could generate a unique link for this email to your app with params that will direct the deferred/deep link.
The good news is, I found a solution. I could construct a web page that redirects the user to the app store, but before doing so, copies some text into their clipboard (without telling them or asking them to do anything). Then later if they install my app I can get the text by pasting from the clipboard. I tested this idea and it works.
The bad news is, starting with iOS 16, Apple now asks you for permission to paste. So if you try to do this, your user will launch your app and immediately get promoted with a message asking them to allow a paste from Safari. I expect most users will deny the request and just the fact that they saw it will erode their trust in the app (I know I wouldn't trust an app that tried consume my clipboard without a direct command from me).

Images in emails are inconsistently being cached in iOS Outlook App

While testing images being loaded from an email in my iOS Outlook app, I see inconsistencies with how the app caches them. These images are loading from external sources (i.e. HTML img tag with src pointing to a server, not images that are embedded/attached). The app makes several requests to the same image source as you navigate around. Some of these requests contain the HTTP_IF_NONE_MATCH header but there is a lot of inconsistency. I don't think it's caching them correctly. I've included more details below. it looks like it's causing my image to be loaded several times when the person is browsing the email/their inbox.
The reason this is a problem for me is that I'm building an email tracking tool that relies on a pixel tracker inside the email. I'm trying to determine how many times my email is opened by its various recipients. So this inconsistency is causing misfires for the tool unfortunately. While I realize that could be considered consequential limitation of relying on the app, I'm wondering if the lack of image caching is a larger issue that could be addressed. It is effectively firing requests to load the image repeatedly so that is eating up mobile data unnecessarily.
Is there a way to improve its caching somehow? I'm also looking for any other ways to determine requests coming from the same phone. Here's what I see in my server log when dealing with an email that contains my pixel tracker.
Push notification for email received on iPhone
Click the app to load the inbox -> Tracker request fired for 1st time (i.e. image loaded for first time)
Open email -> Tracker request fired for 2nd time (without any HTTP_IF_NONE_MATCH header)
Go back to inbox -> Tracker request fired for 3rd time but this time it includes HTTP_IF_NONE_MATCH header. Note previous requests did not include this header even though it's the same URL so some inconsistency indicating it did not cache it
Open email for the second time -> Tracker request fired for 4th time but it did not include the HTTP_IF_NONE_MATCH header (inconsistency with 3rd time, which had header)
Go back to inbox -> No request fired
Open email for third time -> Tracker request fired for 5th time and it included HTTP_IF_NONE_MATCH header (so inconsistency between this and 4th request, which did not include it)
From here on, repeating any of the above steps would trigger requests but would always include the HTTP_IF_NONE_MATCH header successfully. I also tested changing folders, refreshing the inbox, replying to emails etc. While this triggered tracker requests as well, they also included the appropriate header.
However, I noticed that closing the app (by swiping it off) and then opening it again effectively caused the behaviour to reset. The 1st, 2nd and 4th requests would still not include the header while the others would. Note the same happens on data vs wifi.
Generally speaking, it looks like the iOS app is repeatedly loading the images that it should have already cached. Outlook desktop clients work great because it only fires 1 request to load the pixel. For the Outlook Android app, it seems to do a better job caching the image. It makes 2 or 3 requests the first couple of times you open the email but the 2nd/3rd requests always include the header. After that, it stops loading the image altogether so it must be caching it on the phone somehow. Since the Android app functions fairly differently, this is what lead me to believe it may be an issue that could be resolved in the app itself. However, as I said above, I'm looking for alternative ways to determine how to track the user.
Another way I normally rely on is to set a cookie to indicate an open just happened by that device. I then simply skip these false positives to avoid the repeated requests. However, because of the nature of iOS apps needing to whitelist third-party cookies of web requests within the code, each subsequent request is not sending my cookie along either. Here's a related question as well. I confirmed the Safari settings do not block 3rd party cookies in case it conflicts.
Alternatively, if there's another way to tell a unique device, I could figure out how to skip repeated opens for that phone on the server. I checked the rest of the request headers. The only thing that's somewhat identifiable is a combination of user-agent and IP address but that seems very unreliable to me. Two people in the same office with the same corporate phone could be on the same wifi so I think that would fire false negatives instead.
Is there another way to determine the device is opening it multiple times? Ideally if it sent a unique identifier or something, that would be very useful.
Is there a way to force the app to cache the image (this would heavily reduce the misfires) via say some response header?

Are Universal Links cached in iOS? Do they work offline?

I tested Universal Links in iOS by turning on Airplane mode and saw that the correct application was opened (instead of a website)
This indicates some level of "caching" the apple-app-site-association.
I want to determine the extent to which this is cached, so I can determine
What UX edge cases are there (e.g. Offline for x days)
What security considerations are there (e.g. MITM / SSLStrip + .well-known/URL)
etc.
Ideally I would like to have details if additional logic is employed (conditional caching if HTTPS employed, DNSSec, etc)
The exact behavior here is (intentionally?) unclear from Apple. Here is my personal experience, gleaned partly from official documentation and partly from helping thousands of apps implement Universal Links at Branch.io.
The apple-app-site-association file is cached once when the app is first installed.
If this initial scrape fails, in almost all situations it will not be reattempted. The only exception to this is if the initial return is a 5xx error, in which case a limited number of retries may occur. This is not well-documented, and is not covered in Universal Links documentation at all. You can find a mention in the Shared Web Credentials docs.
The file is not checked at all when a Universal Link is opened. This is why you are able to get Universal Links behavior in airplane mode.
The file does not expire. Once it is cached, it sticks permanently for as long as the app is installed.
The file will be re-checked when installing an app update.
The file must be accessible via a valid SSL connection at either https://example.com/apple-app-site-association or https://example.com/.well-known/apple-app-site-association. If there are redirects of any kind, this will fail.
It is theoretically possible to MITM the request if you are able to install a new SSL certificate directly on the device in question. Charles Proxy for example uses this approach for debugging. I have never seen or heard of this being exploited, and the damage would be quite limited because the domain still has to be specified inside the app itself.
I found a way to get around the caching issue. The cache is bound to the domain name, so for every time you want iOS to request apple-app-site-association you can create a new subdomain, and configure iOS to use that subdomain as the universal link for your app.
Extremely hacky, but it is the only workaround that worked for me.

universal links with redirects using google url shortener

The use case is, essentially, this:
the user create some content and uploads it to our server.
our server responds with the URL.
the user sends the URL (eg via text message) to another user.
the other user clicks on the URL. If they have the app installed, they should be taken to the content in the app. If they don't have it, they should still be able to view the content on our site (eg in safari).
This is easy enough, and we have that working, except our URLs are long and we'd like to use shortened URLs. With shortened URLs, the problem is it always opens in Safari, instead of the app, unless we setup a custom domain. (This is described in many places, including here: iOS Universal Links and URL Shorteners).
The docs for google URL shortener indicate that they have overcome this somehow:
Even though App Indexing for iOS is available only in limited release, you can still enable iOS app deep links with goo.gl by implementing App Indexing for iOS. While these deep links may not begin appearing in Search results, they will start working with goo.gl links.
So I installed the app indexing for iOS into our app on a test device and ran it. Then I created a short link but it still opens in my browser, not my app.
Does this really work as advertised? Do I have to wait longer? Install the indexer on more apps? Will a created link open in the app right away, or does the content have to be indexed?
...Or am I missing something else?
Related:
Google app indexing for iOS and universal links
UPDATE:
The only way I can see this actually working without a custom domain is if Google added every app they indexed to their apple site association file. All I see is google apps there, so obviously that's not the case.
Stack overflow won't let me link it because it thinks it's a link shortener, but it's close to this:
https://goo. gl/apple-app-site-association
You are exactly right: for this to work, Google would need to add your app to their apple-app-site-association file. Unfortunately that would be impossible even if Google wanted to do so, because Apple puts a size limit of 128 kb on that file.
Integrating the App Indexing SDK was a good thought, but doesn't solve this issue either.
What you need is a (free) service like Branch.io (full disclosure: I'm on the Branch team). This is specifically designed for exactly what you're trying to accomplish, and takes care of all the housekeeping tasks you are running into. You'll be able to create branded short URLs that take you to your app (if installed) or website fallback (if not installed), and the AASA file will be generated automatically for the short URL domain.

Mobile Safari prompting Windows/NTLM authentication for some media (e.g., MP4)

Right, bear with me on this, I'll try to explain it the best I can.
I have a web application that is running under Windows (Active Directory, NTLM) Authentication. Within this application, I have a HTML <video> element pointing to a .mp4 file on the server.
I access the application, and get prompted (by the browser) to enter credentials. I do so, and I have access to the application, and the video plays.
Works fine on a desktop (Chrome, etc.), but when I fire it up in Safari on an iPad (iOS 8+), I get a secondary credentials prompt when the video is loaded (and another prompt for each and every subsequent video rendered). If I enter correct credentials here, the video plays, no problem. If I cancel the prompt, the video doesn't play. If I navigate away from the page, and go back to the video, I get prompted for credentials again.
Looking at the server logs (IIS 7.5), I see 3 requests for every resource from Safari, the first 2 being returned as 401.2, and the final one returned as 200 (or 206 for .mp4).
What I can't understand is why the .mp4 request prompts for the credentials again, but all other resources work as expected. I've got a suspicion that other media types cause this behaviour too, but I haven't been able to nail them down yet.
I've read comments here and there that Safari sandboxes its media, and as authentication is not passed through to it, it needs to establish authentication again. Even though that kinda feels like what's happening, I'd like to have some proper documentation to point to if this is the case.
Otherwise, does anyone know how to prevent subsequent authentication prompts once the user has already been authenticated, specifically when media (mp4) is rendered?
Seems like i have found a solution to suppress the authentication popups at least in android. To check if this works for safari too, try to include the below in your web.config file of the target site hosted in IIS. I faced the same issue and I am trying to play mp4 files from a SharePoint (IIS) site in chrome on an android device (v. 6.1).
<browserCaps>
<result type="System.Web.Mobile.MobileCapabilities, System.Web.Mobile, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a"/>
<filter>isMobileDevice=false</filter>
</browserCaps>
You might as well need to disable windows authentication and enable anonymous authentication for it to work. It is only a workaround and cannot be an ideal solution because if I am logged in to the site, I cannot play the video. But if I try to access the site anonymously and play mp4 using HTML5 video tag, it works fine. Probably windows authentication is messing with the video playback on mobile devices.
See this link as well.

Resources