Category Archives: coding

Adventures in app writing and publishing

Apple Reviewers can Punish You

tl;dr – Apple policy may now say they won’t hold up your urgent bugfix, but that doesn’t stop them holding it ‘in review’ for an unusually long time so that it is never actually released…

I have had plenty of ‘robust discussions’ with App Review. Sometimes they come round to my way of thinking – I have had several appeals approved. Sometimes Apple just isn’t budging. Until this occasion though they have always been polite and engaged in good faith. I have never felt that a reviewer was punishing me out of spite. This time, I feel like I really got a ‘Bad Apple’ at Apple.

This particular Apple Review nightmare kicked off when a reviewer decided that my bugfix release:

  1. Enabled auto-launch without the user’s permission
  2. Had an app preview video which breaks the rules

Convincing them that they were wrong about #1 was easy. I just had to show the screenshot where my app asks the user if they want to enable the recommended settings and explicitly lists ‘auto-launch’ as one that will be enabled.

Number 2 was harder. Here is the video causing the problem:

For context, this video has been in place for about 18 months, and has (successfully) gone through about 30 reviews so far. You can see it now in the app store listing.

Multi Monitor Wallpaper is an app that sets the wallpaper across multiple monitors. It really needs a way in the app preview to show the multiple monitors in action. So – it ‘zooms out’ allowing you to see the full effect.

This, my reviewer insists breaches the (unwritten) rule

Your app preview includes content that does not sufficiently reflect the app in use. Specifically, your preview:

– Includes device images and/or device frames.

I understand where the frames thing comes from. Apple don’t want a video of people using their Mac in the coffee shop with the app running. They want to see the app itself.

In my case though – the monitors (and frames) _are_ the app. I think that makes this a reasonable and honest app preview. The reviewers when I first submitted the preview 18 months ago obviously agree, and none of the 30ish reviews since then have had a problem with it.

Nonetheless, my reviewer wasn’t budging. They said:

We advise appeal this review by sending a request to the App Review Board. As you may be aware, the App Review Board was created for developers to appeal an app review they have concerns with.
Once the App Review Board has completed their evaluation, they will contact you directly.

Recently, Apple published new guidelines which promised developers that

Bug Fix Submissions: For apps that are already on the App Store, bug fixes will no longer be delayed over guideline violations except for those related to legal issues.

https://developer.apple.com/news/?id=xqk627qu

I really like the new policy. It seems reasonable. This certainly was a bug fix submission. It fixes a crashing bug when users click on one of my image search providers (Unsplash)

I asked:

I did see your message suggesting that I should appeal to the app review board. I’m will do that today.

In the meantime, there is a significant bug which this version fixes (there is an immediate crash if you click to browse Unsplash).
As per your press release, I understand that ‘bug fixes will no longer be delayed over guideline violations except for those related to legal issues.’, so would appreciate it if you could publish this update as soon as possible.

And, I submitted my appeal, and copied it into the resolution centre to keep my reviewer up to date.

Hello Rob,

At this time, you will need to follow the pending guidance from the App Review Board.

I explained that I wasn’t aware of any pending guidance and asked again

Bug Fix Submissions: For apps that are already on the App Store, bug fixes will no longer be delayed over guideline violations except for those related to legal issues.[…]

this is a bug fix submission. I haven’t changed the AppPreview video. I would like to take advantage of this process.
I will address this issue in my next submission if my appeal is not supported by the Appeal Board

still ‘computer says no’

Hello Rob,

Thank you for your response.

To clarify, the App Review Board will be in contact with you, as you currently have a pending appeal.

Best regards,

I tried again

I’m happy for the review board to be in contact with me.
As you say – I have a pending appeal (at your explicit suggestion)

Apple have communicated publicly (via press release and direct email) that ‘bug fixes will no longer be delayed over guideline violations except for those related to legal issues.’

If this is indeed a guideline violation, it certainly doesn’t relate to legal issues.

I’m asking you to honour that explicit public commitment.

that got me close to what I needed

Thank you for providing this information.

If this is a bug fix submission, you may elect to have it approved at this time.

If you would like to take advantage of this opportunity, please respond in Resolution Center to confirm that you can address these issues in your next submission. Additionally, please let us know if you have any questions about how to resolve these issues. If you believe this decision was made incorrectly, you may appeal your app rejection. You may also provide feedback on our review guidelines.

well – I must admit I thought the reviewer was just throwing up an extra step here to be annoying, but I confirmed. Shortly later, I got the promising response

Thank you for providing this information.

We will continue the review, and we will notify you if there are any further issues.


Now. We need a little diversion. How long does a review take?
I have put quite a few updates on Multi Monitor Wallpaper.

This is how long the recent reviews took from the point where they moved to the ‘In Review’ status.

  • 9-Sept, 5 mins
  • 8 Sept, 16 mins
  • 25 July, 20mins
  • 23 July, 20 mins
  • 21 July, 24 mins
  • 16 July, 7 hrs
  • 24 Jun, 1hr 40mins
  • 11 Jun, 6hrs

Mostly about 20 mins. Sometimes 6 or 7 hours.


How long do you think it takes for a very simple bugfix with no changes to the overall app – where Apple is allowing it through because of their commitment ‘not to hold up bugfix releases’ ?

I don’t know the answer to that.

My app changed status to ‘In Review’ on the 11 Sep 2020 at 23:27

It has been over 60 hours so far and I am still waiting.

After 24 hours, I even submitted a request for an expedited review. That was granted – but nothing has happened yet.

Perhaps I have just been unlucky, and the reviewer who seemed to deliberately throw up steps to avoid allowing my bugfix until I asked whether Apple were good to their word; Perhaps that reviewer just had a family emergency and accidentally left my app in the queue.

I think they’re punishing me.

They’re also punishing our shared customers who currently have to use a crashing app.

I’ll keep this post updated.


Update. 68 hours after moving to ‘In Review’, Multi Monitor Wallpaper was finally approved.

Remember that this was the process to ‘not hold up an urgent bugfix release’


Note – quotes of discussions with App Review are fairly heavily edited for brevity, in that they don’t show everything said. Everything quoted is verbatim though.

If any press want full details, I’ll be happy to share the complete conversation.

Google/Apple. Requiring the Account Holder to do techie things is BAD SECURITY!

tl;dr – in the name of security, you encourage me to share passwords.

Photo by Jon Moore on Unsplash

Both the Apple App Store, and the Google Play store allow business accounts to have multiple users.

This means that my client (the app owner) can own their account, and they can let me (the developer) do what I need to to develop and publish apps.

This means we don’t have to share passwords, and the account holder can limit what I have access to. So, for example I might be able to update apps – but I can’t see their financial reports. This all makes lots of sense.

Unfortunately, both Apple and Google have technical actions where they require the account holder to perform them. Because the actions are pretty technical, if the account holder is a business owner rather than a techie – they probably don’t have the skills to perform them. I hit these both recently.

In both cases, they’re important security-sensitive actions. For Apple – it was creating Developer ID Certificates to let me upload a MacOS Catalyst app to the store. For Google, it was enabling API access to automate uploading new builds.

Both of these actions are absurdly technical for a non-tech person to complete. Follow the links if you want the gory details!*

This means that the only practical way to perform these necessary actions (if you’re not physically located in the same place) is for the account owner to share their password with me the developer. This is clearly terrible security practice – and exactly what the multi-user system is set up to avoid.

I completely understand that these are security-critical steps. It makes sense that the account holder should have some kind of approval when they happen. This could be an explicit post-action approval:

‘Rob has requested XXXX – this is a critical security issue. Do you want to approve this action’

Or it could be a time-limited user permission:

‘Grant Rob permission to do XXX for the next 24 hours’

The current system achieves the opposite of what it sets out to do. It sets out to keep security-critical actions safe, but what it encourages is that the developer probably gets the account holder’s password and complete access to everything.


*for bonus foolishness – in the case of the Apple action. Xcode will automatically generate your certificates if you add the account holder’s account to Xcode. This means that it is complicated and techie for the business person to perform the actions (they don’t have Xcode installed) – but automated for the developer if they can just get the account holder’s password.

Dolby Codecs, Legal Threats: Coda

Back in 2014, I wrote about how Dolby were requiring me to remove ac3 support from VLC Streamer for somewhat questionable legal reasons

I included the email I received from their representative about the price I would have to pay

You should also know that there are fees associated with becoming licensed.  Specifically, there is a $25,000 one-time initial fee and a recurring $5,000 annual maintenance fee.  There is also a per-unit royalty that has a tiered structure, due quarterly, based on annual total usage, as follows:

0-100,000 downloads at $0.99 per download

100,001-1,000,000 downloads at $0.67 per download

1,000,001+ downloads at $0.45 per download

I was interested to get a call from a lawyer working for Adobe recently. They were being sued by Dolby for something related to these patents.

Bizarrely, Dolby were arguing that their pricing levels were so super secret that they couldn’t even disclose them in court.

Adobe found my old post and argued that if they were published on the web – they couldn’t be that secret.

I don’t have any details about the case, but I know they settled and it went away. Hopefully my pricing info made the difference…

Adding Codeable to @Published

Codable is a kind of magic.

@Published certainly behaves like magic.

But if you try to add a @Published property to your codeable, then XCode complains

This one had me frustrated for many hours. The issue is that the encoder gets an instance of Published<Type> to encode. As far as I know there isn’t a proper way to get the actual value.
(normally, your code will call the getter on wrappedValue, but I’m not aware of a way to call that directly with Published)

In the end, the only solution I found was to Mirror the struct and extract the value from the ‘value’ Mirror.Child

This has been pretty typical of my SwiftUI experience. There is lots of magical functionality that falls out for minimal effort in a magical way.

But then you try to push the edges, act like a programmer and extend things – and you find that the basic API seems designed to frustrate you. Why would the Published struct not have a simple way to access the wrapped variable?

Anyway, for now at least – we can hack around the limitations

import Foundation
import SwiftUI

extension Published:Encodable where Value:Decodable {

    public func encode(to encoder: Encoder) throws {

        let mirror = Mirror(reflecting: self)
        if let valueChild = mirror.children.first(where: { (child) -> Bool in
            child.label == "value"
        }) {
            if let value = valueChild.value as? Encodable {
                do {
                    try value.encode(to: encoder)
                    return
                } catch let error {
                    assertionFailure("Failed encoding: \(self) - \(error)")
                }
            }
            else {
                assertionFailure("Decodable Value not decodable. Odd \(self)")
            }
        }
        else {
            assertionFailure("Mirror Mirror on the wall - why no value y'all : \(self)")
        }
    }
}

extension Published:Decodable where Value:Decodable {
    public init(from decoder: Decoder) throws {
        self = Published(initialValue:try Value(from:decoder))
    }
}

Apple: You recompiled. Let’s make that crash now.

tl;dr – UIApplication.shared.idleTimerDisabled now causes an undocumented crash if you compile with the iOS 13 SDK and use it from a background thread.

Photo by Zach Savinar on Unsplash

VLC Streamer is one of my oldest apps. It has been going strong since 2008!

It’s a pretty complex app with a bunch of different code paths and edge cases. It’s mostly written in Objective-C.

I uploaded a new build on Jun 15, 2019 to deal with some details around new device screens. No problems there.

I uploaded again on November 20th. There were two relevant changes.

  1. I updated the base SDK to 11.0 (from 9.0)
  2. I compiled with the latest XCode using the 13.0 SDK

I woke up on the 22nd to get loads of crash reports. One of my code paths calls this from a background thread:

[[UIApplication sharedApplication] setIdleTimerDisabled:YES]; 

This now causes a crash.

Three things of note here for me

  1. Nothing in the documentation says you can’t call idleTimerDisabled from a background thread.
  2. No code has changed. I just recompiled and resubmitted. The old build worked, the new build crashes.
  3. Why is this even an issue? If Apple really need this flag to be changed on the main thread – couldn’t they dispatch it to main in the implementation?

Of course – better testing would have caught this, but how many of us really have proper UI testing in all of our code paths…

Update:

Building a test app with iOS 9 as the target still gives the crash.

Presumably this means that the change has come from using XCode 11.2.1 and the iOS 13 SDK.

Overreaction vs Sanity. Google Play vs Apple Store.

In the last week or so, both Apple and Google informed me that one of my apps was in a small way breaching store guidelines.

Photo by Jorge Fernandez on Unsplash

I’ll paraphrase both messages here:

One of your apps hasn’t been updated in years. It doesn’t meet current guidelines. If you don’t update it – we’ll remove it in 30 days.

Apple

and

One of your apps breaks the metadata guidelines. It has a quote in the app description.

We have removed it from the store.

Google

Both complaints are probably valid. The iOS app hasn’t been updated since 2015 and hasn’t been optimised for the latest devices. I’ll update it this month.

The Android app did have the following quote in the store description

VLC Remote is the latest Android app to earn my favor, and it’s a beauty

Androidnica

The quote has been there for at least 5 years. I’m not entirely sure whether it should count as a ‘user testimonial’ (banned) or a ‘third party review’ (I think those are ok). But either way – I’m happy to remove it.

Removing my app from the store just seems like a Massive Overreaction when they could simply have emailed me to request a change.

What does a red dot mean Apple?

Every now and again – Apple demands my attention with a red dot on the System Preferences in the dock

When they do – I launch the preferences app, and my eye is immediately drawn to the icon at the top right on the ‘Notifications’ icon

Of course – that red dot isn’t a notification dot. That’s an icon of a notification dot – not an actual notification dot

I’m supposed to ignore that one, and look for the second one on the ‘software update’ icon

That’s just bad UI

Update – Catalina

Apple have fixed this as of Mac OS 10.15