Category Archives: apple

Swift, Obj-C, AppleScript and AppStore fun.

HSNotifications – Easier Better Notifications in Swift

Introducing HSNotifications. A simple, sensible, easy-to-use wrapper around NSNotificationCenter

Let’s jump straight in. I mostly use notifications to keep my UI up to date. That means ViewControllers end up with a bunch of observers that need to be activated and de-activated with the ViewController lifecycle

Easy ViewController Integration

class ViewController: NSViewController, HSHasObservers {
    
    override func viewDidLoad() {
        super.viewDidLoad()

        //Create and add
        HSObserver.init(forName: Foo.didAThing,
                            using: { (notif) in
                                //Do Something
        }).add(to: self)
        
        //Monitor multiple notifications
        HSObserver.init(forNames: [Bar.oneThing,Bar.anotherThing] ,
                            activate:true,
                            using: { (notif) in
                                //Do Something Else
        }).add(to: self)
    }
    
    override func viewWillAppear() {
        super.viewWillAppear()
        
        activateObservers()
    }
    
    override func viewDidDisappear() {
        super.viewDidDisappear()
        
        deactivateObservers()
    }
}

Taking this step by step:

ViewController uses the protocol HSHasObservers

This allows us to add observers to the ViewController (they are stored in the observers array)

Next we create an HSObserver object. The block will be triggered by any Foo.didAThing notification.

We take sensible defaults

  • Assume you want to use NSNotificationCenter.default
  • Assume you want your block to fire on the main queue
  • Assume you don’t care what object broadcasts the notification.

(Of course – you can override any of these if you want to.)

The observer is added to the ViewController with .add(to:self)

Next we add an HSObserver to observe multiple Notifications

Finally, the observers are activated and deactivated in viewWillAppear and viewDidDisappear

When the ViewController is released, they are cleaned up automatically.

Standalone Observers

    var waveObserver:HSObserver
    init() {
        waveObserver = HSObserver.init(forName: Watcher.wave,
                                           using: { (notif) in
            //Do Something
        })
        
        //activate
        waveObserver.activate()
        
        //deactivate
        waveObserver.deactivate()
    }

HSObserver objects can be stored as a standard variable.

This allows them to be activated and deactivated.

They clean up properly when they are released with the owning object.

There are of course lots of options available here.

    /// Create observer
    ///
    /// - parameter name:  notification name
    /// - parameter obj:   object to observe (default nil)
    /// - parameter queue: queue to run the block on (default main)
    /// - parameter center: notification center (default NotificationCenter.default)
    /// - parameter block: block to run (beware of retain cycles!)
    ///
    /// - returns: unactivated manager. Call activate() to start
    convenience init(forName name: NSNotification.Name, 
                     object obj: Any? = nil,
                     queue: OperationQueue? = .main,
                     center newCenter: NotificationCenter = NotificationCenter.default,
                     activate: Bool = false,
                     using block: @escaping (Notification) -> Swift.Void)

Get HSNotification at GitHub

Secret Mac App Store Rule – Minimum Trial Length

I recently started experimenting with free trials in the Mac App Store.

Photo by AbsolutVision on Unsplash

The first App I changed is Icon Tool. This is an incredibly simple app that lets developers generate icon assets for iOS or Mac OS apps.

Because the app is so simple, I only wanted to give a short trial. Just long enough for you to see how it works. The relevant app store rule is:

3.1.1  In-App Purchase:

Non-subscription apps may offer a free time-based trial period before presenting a full unlock option by setting up a Non-Consumable IAP item at Price Tier 0 that follows the naming convention: “XX-day Trial.”

So, I created a 1-day Trial IAP item and submitted my app. It was rejected with the reason:

‘We found that your app includes an in-app purchase free trial period, but the free trial period is shorter than the minimum 3 days.’

I have asked for clarification on where/if the 3 day rule is documented and got the response:

‘We understand that you may not agree with the feedback we have provided. However, to ensure App Store customers a safe and enjoyable experience, all apps must comply with the App Store Review Guidelines.’

I have no argument with this statement. My issue is that the 3 day rule doesn’t exist in the published guidelines

I submitted an appeal essentially asking for clarification on whether this was really a rule, and if so – where/whether it was published.

The appeal responded with a section of text which did indeed describe the 3-day minimum. That text isn’t in the published guidelines though (and frustratingly, I didn’t save it).

So – It’s a rule. A secret rule, but one I have to follow.

Boofing Supreme – Rejected!

Coming Soon

Boofing Supreme

Sound Credits: Mike Koenig, http://soundbible.com/

Update: Apple was not amused. Boofing Supreme was rejected…

Supreme court judge Brett Kavanaugh testified that that the ‘boofing’ referred to in his yearbook referred to flatulence – so I’d hoped this might get through on the basis of sworn testimony, or satire…

Mac OS Developers – Easily add Right-Click actions.

Right Click Booster makes it really easy for developers to add their own Right-Click actions.

OSX 10.10 allows developers to build FinderSync extensions.
These allow you to add right.click (or cmd+click) actions within the finder.

However – you can only do this with App-Store apps, and building finder-sync extensions is a massive pita.

Right Click Booster now makes it super-easy for developers to add right-click actions for their own apps.

The full code within VLC Streamer Helper is:


[RCBRightClick registerExtensionWithName:@"Add to VLC Streamer"
scheme:@"vlcsaddfile"
filetypes:@[@"mp4",@"avi",...]
image:[NSImage imageNamed:@"menuIcon"]
callbackScheme:nil];

So – if you’re a developer, find out all about it here

If you use software that would benefit from right-click integration – then please email the developer and let them know about Right Click Booster.

Dolby codecs, software patents, legal threats

Short version:

If you copy movies to VLC Streamer using iTunes, then as from version 4.12, you’ll get a warning message and no sound for movies using these Dolby codecs.

  • Dolby Digital (AC3)
  • Dolby Digital Plus (E-AC3)
  • Dolby TrueHD (MLP)

The reason for this is that Dolby claim that playing sound encoded in those codecs would breach their patents. Although this is arguable – it isn’t in practice something I can fight.

The workaround is fairly simple; Instead of copying your movies via iTunes, you should stream them from the helper app (the helper app uses the desktop version of VLC to do the conversion).

In the paid version, you can also copy movies using the helper app so that you can watch them when you are away from home.

Long version:

Before I get into the details, I want to be very clear that Dolby’s representative was a pleasure to work with. He was perfectly reasonable and courteous. I couldn’t have asked for a nicer legal shakedown. I don’t believe that Dolby’s demands were valid – but he was doing his job in a perfectly professional manner.

On the 22nd November, I got a notice from Apple via the AppStore.

On 10/14/2014, we received a notice from Dolby Laboratories that Dolby Laboratories believes your apps listed below infringe their intellectual property rights. In particular, Dolby Laboratories believes you are infringing their copyright. Please see their comments below.

You can reach Dolby Laboratories through [redacted], copied on this email.

We look forward to receiving written assurance that your applications do not infringe Dolby Laboratories’s rights, or that the parties are taking steps to promptly resolve the matter.  Please keep us apprised of your progress.

[snip]

Comments from Complainant: The App(s) indicated contain and/or practice Dolby’s intellectual property, including patents and copyrighted source code and/or pseudocode, namely Dolby Digital (AC3), Dolby Digital Plus (E-AC3), and/or Dolby TrueHD (MLP) without authorization.

The ability to play this kind of movie was a fairly recent addition. In version 4.0 (released at the start of October), I added MobileVLCKit to VLC Streamer to handle movies copied through iTunes that don’t play in the system player.

MobileVLCKit is the engine that powers the VLC app on iOS, so it is capable and powerful. You can tell that VLC Streamer is playing something with MobileVLCKit if you see an orange screen at the start of playback. It is MobileVLCKit which plays these movies, and MobileVLCKit which I eventually had to hobble to stop VLC Streamer from being removed from the AppStore.

I asked how much it would cost to licence the patents. Playing these movies was a new and smallish feature – but clearly valuable to some people, so I’d have been willing to pay something.

…I’m glad you’re interested in becoming properly licensed.  We have a standard process for that which begins by filling out this online form (it just captures generic info like contact data, etc):

http://www.dolby.com/us/en/professional/licensing/apply-license-consumer.aspx

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

Remember that this would apply to the free version of VLC Streamer as well as the paid version. Clearly this is not an option.

I contacted a senior Developer involved with VLC and asked for an opinion. His opinion was that the patent claims were bogus.

I didn’t write the code for VLC, and I’m not an expert on patent law, but I know that software patents are at the very least controversial in Europe.

The VLC legal page shows their interpretation.

‘Neither French law nor European conventions recognize software as patentable […]. Therefore, software patents licenses do not apply on VideoLAN software.’

Incidentally, this is presumably why Dolby haven’t stopped VLC from distributing the desktop player which plays the exact same codecs. The VLC desktop version is what does the conversion of your videos in the helper so that they can be streamer to VLC Streamer.

The full list of Dolby’s patent claims is given at the bottom of the list.

Nonetheless, it is clear that unless I was willing to spend ridiculous sums on lawyers, Dolby’s claims to Apple would be sufficient to get VLC Streamer closed down.

Personally, I believe software patents are a terrible idea. I’m not alone in that. Other than donating to the Pirate Party and organisations like the EFF and the Open Rights Group, there isn’t much I can do.

To round up, here is the list of patents which Dolby claims I was infringing. I did ask for a list split by patent – but my contact at Dolby was unable to provide that.

  • ARGENTINA AR 023444 B1
  • ARGENTINA 023424
  • AUSTRALIA 2002307533
  • AUSTRALIA 2003239126
  • AUSTRALIA 2004211163
  • AUSTRALIA 2004239655
  • AUSTRALIA 2005217943
  • AUSTRALIA 649,786
  • AUSTRALIA 653,582
  • AUSTRALIA 655,053
  • AUSTRALIA 674,357
  • AUSTRALIA 677,856
  • AUSTRALIA 682,913
  • AUSTRALIA 694,131
  • AUSTRALIA 712,719
  • AUSTRALIA 771,454
  • AUSTRALIA 2005204293
  • AUSTRALIA 781629
  • AUSTRIA 0 519 055
  • AUSTRIA 0 520 068
  • AUSTRIA 0 664 943
  • AUSTRIA 0 709 004
  • AUSTRIA 0 709 005
  • AUSTRIA 0 827 647
  • AUSTRIA 0 940 015
  • AUSTRIA 1 175 670
  • AUSTRIA 1 216 474
  • AUSTRIA 1 386 312
  • AUSTRIA 1 590 801
  • AUSTRIA 1 617 418
  • AUSTRIA 1 723 638
  • AUSTRIA 1 173 925
  • BELGIUM 0 519 055
  • BELGIUM 0 520 068
  • BELGIUM 0 664 943
  • BELGIUM 0 709 004
  • BELGIUM 0 709 005
  • BELGIUM 0 827 647
  • BELGIUM 0 940 015
  • BELGIUM 1 175 670
  • BELGIUM 1 216 474
  • BELGIUM 1 386 312
  • BELGIUM 1 590 801
  • BELGIUM 1 617 418
  • BELGIUM 1 723 638
  • BELGIUM 0 826 274
  • BELGIUM 1 173 925
  • BRAZIL PI9805989-0
  • BULGARIA 1 723 638
  • BULGARIA 2 194 528
  • CANADA 2,077,662
  • CANADA 2,077,668
  • CANADA 2,103,051
  • CANADA 2,142,092
  • CANADA 2,164,964
  • CANADA 2,166,551
  • CANADA 2,221,845
  • CANADA 2,368,453
  • CANADA 2,445,480
  • CANADA 2,218,893
  • CANADA 2,365,529
  • CANADA 2,585,240
  • CHINA ZL00806330.3
  • CHINA ZL00813602.5
  • CHINA ZL02809542.1
  • CHINA ZL200310101328.4
  • CHINA ZL200480011250.X
  • CHINA ZL200510107590.9
  • CHINA ZL200580005301.2
  • CHINA ZL200710137399.8
  • CHINA ZL201010166094.1
  • CHINA ZL96113286.8
  • CHINA ZL96122821.0
  • CHINA ZL98800792.4
  • CYPRUS 2 088 583
  • CZECH REPUBLIC 1 590 801
  • CZECH REPUBLIC 1 723 638
  • DENMARK 0 519 055
  • DENMARK 0 520 068
  • DENMARK 0 587 733
  • DENMARK 0 664 943
  • DENMARK 0 709 004
  • DENMARK 0 709 005
  • DENMARK 0 827 647
  • DENMARK 0 940 015
  • DENMARK 1 175 670
  • DENMARK 1 216 474
  • DENMARK 1 386 312
  • DENMARK 1 590 801
  • DENMARK 1 617 418
  • DENMARK 1 723 638
  • DENMARK 1 173 925
  • ESTONIA 2 088 583
  • ESTONIA 2 194 528
  • FINLAND 0 940 015
  • FINLAND 1 175 670
  • FINLAND 1 216 474
  • FINLAND 1 386 312
  • FINLAND 1 590 801
  • FINLAND 1 617 418
  • FINLAND 1 723 638
  • FINLAND 0 826 274
  • FRANCE 0 519 055
  • FRANCE 0 520 068
  • FRANCE 0 587 733
  • FRANCE 0 664 943
  • FRANCE 0 709 004
  • FRANCE 0 709 005
  • FRANCE 0 757 506
  • FRANCE 0 827 647
  • FRANCE 0 940 015
  • FRANCE 1 175 670
  • FRANCE 1 216 474
  • FRANCE 1 386 312
  • FRANCE 1 590 801
  • FRANCE 1 617 418
  • FRANCE 1 723 638
  • FRANCE 2 194 528
  • FRANCE 0 826 274
  • FRANCE 1 173 925
  • GERMANY 0 520 068
  • GERMANY 0 664 943
  • GERMANY 0 709 004
  • GERMANY 0 757 506
  • GERMANY 0 940 015
  • GERMANY 1 175 670
  • GERMANY 1 216 474
  • GERMANY 1 386 312
  • GERMANY 1 590 801
  • GERMANY 1 617 418
  • GERMANY 1 723 638
  • GERMANY 2 088 583
  • GERMANY 2 194 528
  • GERMANY 692 14 523.0
  • GERMANY 692 21 616.2
  • GERMANY 694 01 514.8
  • GERMANY 697 13 971.9
  • GERMANY 0 826 274
  • GERMANY 1 173 925
  • GREECE 1 723 638
  • HONG KONG 1030843
  • HONG KONG 1045747
  • HONG KONG 1049401
  • HONG KONG 1070457
  • HONG KONG 1080596
  • HONG KONG 1082093
  • HONG KONG 1092925
  • HONG KONG 1114233A
  • HUNGARY 1 590 801
  • HUNGARY 1 723 638
  • ICELAND 2 088 583
  • INDIA 222223
  • INDIA 235401
  • INDONESIA ID0022057
  • INDONESIA ID0022159
  • INDONESIA ID0024386
  • INDONESIA ID0025693
  • IRELAND 0 940 015
  • IRELAND 1 216 474
  • IRELAND 1 617 418
  • IRELAND 1 723 638
  • IRELAND 2 194 528
  • ISRAEL 169442
  • ISRAEL 171287
  • ISRAEL 177093
  • ITALY 0 519 055
  • ITALY 0 520 068
  • ITALY 0 664 943
  • ITALY 0 709 004
  • ITALY 0 827 647
  • ITALY 0 940 015
  • ITALY 1 175 670
  • ITALY 1 216 474
  • ITALY 1 386 312
  • ITALY 1 590 801
  • ITALY 1 617 418
  • ITALY 1 723 638
  • ITALY 0 826 274
  • ITALY 1 173 925
  • JAPAN 2766466
  • JAPAN 3197012
  • JAPAN 3203250
  • JAPAN 3297051
  • JAPAN 3421343
  • JAPAN 3449715
  • JAPAN 3761639
  • JAPAN 3804968
  • JAPAN 4033906
  • JAPAN 4035631
  • JAPAN 4213708
  • JAPAN 4290997
  • JAPAN 4345890
  • JAPAN 4511443
  • JAPAN 4689625
  • JAPAN 4782685
  • JAPAN 4843142
  • JAPAN 3,715,653
  • JAPAN 4610087
  • LIECHTENSTEIN 0 519 055
  • LIECHTENSTEIN 0 520 068
  • LIECHTENSTEIN 0 664 943
  • LIECHTENSTEIN 0 709 004
  • LIECHTENSTEIN 0 709 005
  • LIECHTENSTEIN 0 827 647
  • LIECHTENSTEIN 0 940 015
  • LIECHTENSTEIN 1 175 670
  • LIECHTENSTEIN 1 216 474
  • LIECHTENSTEIN 1 386 312
  • LIECHTENSTEIN 1 590 801
  • LIECHTENSTEIN 1 617 418
  • LIECHTENSTEIN 1 723 638
  • LIECHTENSTEIN 1 173 925
  • LITHUANIA 2 088 583
  • LUXEMBOURG 2 088 583
  • MALAYSIA MY-122486-A
  • MALAYSIA MY-138877-A
  • MALAYSIA MY-140567-A
  • MALAYSIA MY-142955-A
  • MALAYSIA MY-143979-A
  • MALAYSIA MY-123651-A
  • MEXICO 223934
  • MEXICO 254932
  • MEXICO 262752
  • MEXICO 267655
  • MEXICO 281099
  • MONACO 2 088 583
  • NETHERLANDS 0 519 055
  • NETHERLANDS 0 520 068
  • NETHERLANDS 0 587 733
  • NETHERLANDS 0 664 943
  • NETHERLANDS 0 709 004
  • NETHERLANDS 0 709 005
  • NETHERLANDS 0 827 647
  • NETHERLANDS 0 940 015
  • NETHERLANDS 1 175 670
  • NETHERLANDS 1 216 474
  • NETHERLANDS 1 386 312
  • NETHERLANDS 1 590 801
  • NETHERLANDS 1 617 418
  • NETHERLANDS 1 723 638
  • NETHERLANDS 0 826 274
  • NETHERLANDS 1 173 925
  • POLAND 1 723 638
  • PORTUGAL 0 940 015
  • PORTUGAL 1 216 474
  • PORTUGAL 1 617 418
  • PORTUGAL 1 723 638
  • ROMANIA 1 590 801
  • ROMANIA 1 723 638
  • RUSSIA 2236046
  • RUSSIA 2256293
  • SINGAPORE 117171
  • SINGAPORE 124836
  • SINGAPORE 144743
  • SINGAPORE 99819
  • SINGAPORE P0047116
  • SINGAPORE P0047709
  • SINGAPORE P0048278
  • SINGAPORE P0049883
  • SINGAPORE P0049884
  • SINGAPORE P0050974
  • SINGAPORE P0054317
  • SINGAPORE P0066321
  • SINGAPORE P0082553
  • SINGAPORE P0084124
  • SINGAPORE P0083964
  • SLOVAKIA 2 088 583
  • SLOVAKIA 2 194 528
  • SLOVENIA 2 088 583
  • SLOVENIA 2 194 528
  • SOUTH KOREA 10-0214252
  • SOUTH KOREA 10-0228687
  • SOUTH KOREA 10-0228688
  • SOUTH KOREA 10-0893281
  • SOUTH KOREA 10-0945673
  • SOUTH KOREA 10-0992081
  • SOUTH KOREA 10-1005731
  • SOUTH KOREA 10-1085477
  • SOUTH KOREA 220,862
  • SOUTH KOREA 253136
  • SOUTH KOREA 259559
  • SOUTH KOREA 285993
  • SOUTH KOREA 424036
  • SOUTH KOREA 10-0915120
  • SPAIN 0 519 055
  • SPAIN 0 520 068
  • SPAIN 0 664 943
  • SPAIN 0 709 004
  • SPAIN 0 709 005
  • SPAIN 0 827 647
  • SPAIN 0 940 015
  • SPAIN 1 175 670
  • SPAIN 1 216 474
  • SPAIN 1 386 312
  • SPAIN 1 590 801
  • SPAIN 1 617 418
  • SPAIN 1 723 638
  • SPAIN 0 826 274
  • SPAIN 1 173 925
  • SWEDEN 0 519 055
  • SWEDEN 0 520 068
  • SWEDEN 0 664 943
  • SWEDEN 0 709 004
  • SWEDEN 0 827 647
  • SWEDEN 1 175 670
  • SWEDEN 1 216 474
  • SWEDEN 1 386 312
  • SWEDEN 1 590 801
  • SWEDEN 1 617 418
  • SWEDEN 1 723 638
  • SWEDEN 512719
  • SWEDEN 0 826 274
  • SWEDEN 1 173 925
  • SWITZERLAND 0 519 055
  • SWITZERLAND 0 520 068
  • SWITZERLAND 0 664 943
  • SWITZERLAND 0 709 004
  • SWITZERLAND 0 709 005
  • SWITZERLAND 0 827 647
  • SWITZERLAND 0 940 015
  • SWITZERLAND 1 175 670
  • SWITZERLAND 1 216 474
  • SWITZERLAND 1 386 312
  • SWITZERLAND 1 590 801
  • SWITZERLAND 1 617 418
  • SWITZERLAND 1 723 638
  • SWITZERLAND 1 173 925
  • TAIWAN 180037
  • TAIWAN 324762
  • TAIWAN 91693
  • TAIWAN I350107
  • TAIWAN I 226,041
  • TURKEY 1 386 312
  • TURKEY 1 590 801
  • TURKEY 1 723 638
  • TURKEY 2 194 528
  • UNITED KINGDOM 0 519 055
  • UNITED KINGDOM 0 520 068
  • UNITED KINGDOM 0 587 733
  • UNITED KINGDOM 0 664 943
  • UNITED KINGDOM 0 709 004
  • UNITED KINGDOM 0 709 005
  • UNITED KINGDOM 0 757 506
  • UNITED KINGDOM 0 827 647
  • UNITED KINGDOM 0 940 015
  • UNITED KINGDOM 1 175 670
  • UNITED KINGDOM 1 216 474
  • UNITED KINGDOM 1 386 312
  • UNITED KINGDOM 1 590 801
  • UNITED KINGDOM 1 617 418
  • UNITED KINGDOM 1 723 638
  • UNITED KINGDOM 2 194 528
  • UNITED KINGDOM 0 826 274
  • UNITED KINGDOM 1 173 925
  • UNITED KINGDOM 2 323 754
  • UNITED STATES 5,291,557
  • UNITED STATES 5,394,473
  • UNITED STATES 5,581,653
  • UNITED STATES 5,583,962
  • UNITED STATES 5,623,577
  • UNITED STATES 5,632,003
  • UNITED STATES 5,633,981
  • UNITED STATES 5,890,106
  • UNITED STATES 6,016,295
  • UNITED STATES 6,246,345
  • UNITED STATES 6,978,236
  • UNITED STATES 7,181,389
  • UNITED STATES 7,313,519
  • UNITED STATES 7,318,027
  • UNITED STATES 7,318,035
  • UNITED STATES 7,516,064
  • UNITED STATES 8,036,880
  • UNITED STATES 6,611,212
  • UNITED STATES 6,664,913
  • UNITED STATES 6,774,820
  • UNITED STATES 6,784,812
  • UNITED STATES 6,891,482
  • UNITED STATES 7,193,538

 

Note for media – I haven’t published the details of the Dolby representative as I don’t want him being spammed. If you need to contact him to confirm details, or seek comment, then contact me via rob at hobbyistsoftware.com