Adding a subdomain with Certbot

October 16th, 2017

It’s relatively straightforward to have multiple domains and sub-domains use the same Certbot certificate when they all point to the same document root. Adding a sub-domain that points somewhere else is not as easy.

I wanted to add a beta sub-domain for testing a site rewrite. I could get the certificate to generate, but I couldn’t figure out how to modify the Apache config files for the beta. This is how I did it.

To figure out what should be done, I ran this code to expand the existing certificate.


sudo /opt/certbot/certbot-auto --installer apache --webroot -w /www/example -d example.com,www.example.com  --webroot -w /www/example_beta -d beta.example.com

To verify that it did what I wanted, I ran:


/opt/certbot/certbot-auto certificates

and got this:


Certificate Name: example.com
    Domains: example.com beta.example.com www.example.com
    Expiry Date: 2018-01-14 19:35:43+00:00 (VALID: 89 days)
    Certificate Path: /etc/letsencrypt/live/www.example.com/fullchain.pem
    Private Key Path: /etc/letsencrypt/live/www.example.com/privkey.pem

I was originally looking at the example.com file in the sites-available directory, but what I should have been looking at was in the Certbot generated files that end in -le-ssl.conf.


<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName example.com
    ServerAlias www.example.com
    ServerAdmin root@example.com

    DocumentRoot /www/example

    CustomLog /var/log/apache2/example.com.access_log combined
    ErrorLog /var/log/apache2/example.com.error_log

    ErrorDocument 404 /missing.php
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
</VirtualHost>

</IfModule>
<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerAlias beta.example.com
    ServerAdmin root@touringmachine.com

    DocumentRoot /www/example_beta

    CustomLog /var/log/apache2/example.com.access_log combined
    ErrorLog /var/log/apache2/example.com.error_log

    ErrorDocument 404 /missing.php
Include /etc/letsencrypt/options-ssl-apache.conf
SSLCertificateFile /etc/letsencrypt/live/www.example.com/cert.pem
SSLCertificateKeyFile /etc/letsencrypt/live/www.example.com/privkey.pem
SSLCertificateChainFile /etc/letsencrypt/live/www.example.com/chain.pem
</VirtualHost>
</IfModule>

You need to run this code after changing the config files.


sudo service apache2 restart

Don’t forget to change your DNS record to add the sub-domain.

Apple Mail Preferences Pane

October 9th, 2017

When updating to the Mac OS High Sierra Beta my computer hung. I let it run for a long time, but was unable to get it to continue. I restored from a backup, but it did not have all of the files for my email. I had to re-enter my email accounts and restore messages manually. Somewhere in the process, Mail app stopped being able to display the Preferences Pane. I added a new user to my Mac and the Preferences Pane showed up fine, so it looked like something in my user preferences was either missing or corrupted. I removed various things from ~/Library/Preferences/com.apple.mail but nothing fixed the problem. Then I stumbled on a StackExchange mentioning that some things are stored in ~/Containers.

Sure enough, removing Container.plist from com.apple.mail caused Mail to regenerate whatever is in that file. I now get all of my preferences back and they appear to be the same as before the crash.

willAnimateRotationToInterfaceOrientation: duration: deprecated

September 27th, 2017

After iOS 8 willAnimateRotationToInterfaceOrientation is no longer supported. After some experimenting I found that a drop-in replacement for:


- (void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)orientation duration:(NSTimeInterval)duration {

     ... code

} 

is


- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator {
    [coordinator animateAlongsideTransition:^(id<UIViewControllerTransitionCoordinatorContext> context)
     {

     ... code

     } completion:^(id<UIViewControllerTransitionCoordinatorContext> context)
     {

     }];
    [super viewWillTransitionToSize:size withTransitionCoordinator:coordinator];
}

In case it isn’t clear, replace the method and then after your existing code, paste in the completion code and call super.

statusBarOrientation deprecated

September 27th, 2017

My apps use code to put objects on the screen and the layout of my apps changes depending on the orientation of the device. I had been using statusBarOrientation to determine the orientation, but it as been deprecated as of iOS 9. It still works in iOS 11 but since I have to update my apps anyway for iPhone X, I decided that now would be as good a time as any to update the code.

I believe the reason for the deprecation is that now apps can appear in a sidebar, so they don’t have a status bar. I have not enabled that behaviour in my apps, so it doesn’t affect me. The recommended way to get the orientation is to look at the screen size.

I had been using this line at the top of each file where I needed to do something depending on orientation.


 UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;

I use a utilities class for things that I use across classes, so I decided to put it there so I could change it easily if I needed to at some point in the future.


+ (NSString *) orientation  {

    CGSize screenSize = [UIScreen mainScreen].bounds.size;
    NSString *deviceOrientation = @"Portrait";
    if (screenSize.height < screenSize.width) {
        deviceOrientation = @"Landscape";
    }
    return deviceOrientation;
}

The replacement code in each class is:


NSString *orientation = [Utilities orientation];

The enum UIInterfaceOrientation has not been deprecated, so I could have returned one of the values and not had to change any other code, but the conditionals are messy and hard to read,


if (orientation == UIInterfaceOrientationPortrait || orientation == UIInterfaceOrientationPortraitUpsideDown)

so I decided to return a string instead to make the code easier to read, e.g.


if ( [orientation isEqualToString:@"Portrait"] ) {

iOS 11 UIBarButtonItem images not sizing

September 21st, 2017

The answer to my question was hinted at in this question on StackOverflow, so I think the answer is to disable autolayout for my UIToolbar view. But I was not sure how to do that with programmatically designed views. Fortunately, someone else knew how to do it.

The code that is said to work for views is


cButton.translatesAutoresizingMaskIntoConstraints = YES;

But I’m not sure if it applies to my code since UIToolbar doesn’t inherit from UIView.

I have lots of small images that I use in my games that are different sizes depending on the device and orientation. Rather than having lots of different images, and adding new ones when Apple introduces new devices, I decided to make one 160×160 image fore each and then resize it when it is used. This worked fine from iOS 4 – iOS 10 but fails in iOS 11.

The code is pretty straightforward:


// Get the image
NSString *pictFile = [[NSBundle mainBundle] pathForResource:@"Correct" ofType:@"png"];
UIImage *imageToDisplay = [UIImage imageWithContentsOfFile:pictFile];
UIImage *cImage  = [UIImage imageWithCGImage:imageToDisplay.CGImage scale:[UIScreen mainScreen].scale orientation:imageToDisplay.imageOrientation];

UIButton *cButton = [UIButton buttonWithType:UIButtonTypeCustom];
[cButton setImage:cImage forState:UIControlStateNormal];
[cButton setTitle:@"c" forState:UIControlStateNormal];

//set the frame of the button to the size of the image
cButton.frame = CGRectMake(0, 0, standardButtonSize.width, standardButtonSize.height);

//create a UIBarButtonItem with the button as a custom view
c = [[UIBarButtonItem alloc] initWithCustomView:cButton];

This is what it looks like pre11. The bar button items have been resized and fit nicely in the bottom bar. Note I reduced the size of the checkmark by 50% just to make sure I was looking at the correct code and that it behaves like I expect.

iOS 10 version of buttons

Here’s what they look like in the simulator for Xcode 9.0 GM and iOS 11. Note that the top row of buttons resize correctly but the bottom row expand to fill the space allocated for the tab bar. The same behaviour happens on iPads as well and various devices.

iOS 10 version of buttons

The answer provided by FallStreak is:
BarButtonItem (iOS11\xCode9) uses autolayout instead of frames. Try this (Swift):


if #available(iOS 9.0, *) {
    cButton.widthAnchor.constraint(equalToConstant: customViewButton.width).isActive = true
    cButton.heightAnchor.constraint(equalToConstant: customViewButton.height).isActive = true
}

The Objective C version that I worked out is:


if (@available(iOS 9, *)) {
     [cButton.widthAnchor constraintEqualToConstant: standardButtonSize.width].active = YES;
     [cButton.heightAnchor constraintEqualToConstant: standardButtonSize.height].active = YES;
}

Well Golly


Atheism Plus

Buy from Amazon