[ACCEPTED]-best way to add license section to iOS settings bundle-settings.bundle
I think I've now managed to solve all the 25 problems I was running into.
- It seems to be best to use group element titles to hold the licenses (this is what Apple do in the iWork apps). There is however a limit on the length of these (and I've not yet discovered exactly what the limit is), so you need to break each license file into multiple strings.
- You can create a line break within these by include a literal carriage return (ie. otherwise known as ^M, \r or 0x0A)
- Make sure not to include any literal "s mid-text. If you do, some or all of the strings in the file will get silently ignored.
I've got a convenience 24 script I use to help generate the .plist 23 and .strings file, shown below.
To use it:
- Create a 'licenses' directory under your project
- Put script into that directory
- Put each license into that directory, one per file, with filenames that end .license
- Perform any necessary reformatting on the licenses. (eg. remove extra spaces at the beginning of lines, ensure that there are no line breaks mid-paragraph). There should be a blank line in-between each paragraph
- Change to licenses directory & run the script
- Edit your settings bundle Root.plist to include a child section called 'Acknowledgements'
Here's 22 the script:
#!/usr/bin/perl -w
use strict;
my $out = "../Settings.bundle/en.lproj/Acknowledgements.strings";
my $plistout = "../Settings.bundle/Acknowledgements.plist";
unlink $out;
open(my $outfh, '>', $out) or die $!;
open(my $plistfh, '>', $plistout) or die $!;
print $plistfh <<'EOD';
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>StringsTable</key>
<string>Acknowledgements</string>
<key>PreferenceSpecifiers</key>
<array>
EOD
for my $i (sort glob("*.license"))
{
my $value=`cat $i`;
$value =~ s/\r//g;
$value =~ s/\n/\r/g;
$value =~ s/[ \t]+\r/\r/g;
$value =~ s/\"/\'/g;
my $key=$i;
$key =~ s/\.license$//;
my $cnt = 1;
my $keynum = $key;
for my $str (split /\r\r/, $value)
{
print $plistfh <<"EOD";
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>Title</key>
<string>$keynum</string>
</dict>
EOD
print $outfh "\"$keynum\" = \"$str\";\n";
$keynum = $key.(++$cnt);
}
}
print $plistfh <<'EOD';
</array>
</dict>
</plist>
EOD
close($outfh);
close($plistfh);
Setting up your Settings.bundle
If you haven't created a Settings.bundle, go 21 to File --> New --> New File...
Under the 20 Resource section, find the Settings Bundle. Use 19 the default name and save it to the root 18 of your project.
Expand the Settings.bundle
group and select 17 Root.plist
. You will need to add a new section where 16 its key will be Preference Items
of type Array
. Add the following 15 information:
The Filename
key points to the plist 14 that was created by this script. You can 13 change the title
to what ever you want.
Execute Script At Build Time
Also, if 12 you want this script to run whenever you 11 build your project, you can add a build 10 phase to your target:
- Go to your project file
- Select the target
- Click the Build Phases tab
- In the lower right corner of that pane, click on 'Add Build Phase'
- Select 'Add Run Script'
- Drag and drop your perl script into the section for your script. Modify to look something like this:
cd $SRCROOT/licenses
($SRCROOT
points to the root of your project)./yourScriptName.pl
After you have finished 9 that, you can drag the Run Script
build phase sooner 8 in the build process. You'll want to move 7 it up before Compile Sources
so that the updates to your 6 Settings Bundle get compiled and copied 5 over.
Update for iOS 7: iOS 7 seems to handle the "Title" key 4 different and is messing up the rendered 3 text. To fix that the generated Acknowledgements.plist 2 needs to use the "FooterText" key instead 1 of "Title". This how to change the script:
for my $str (split /\r\r/, $value)
{
print $plistfh <<"EOD";
<dict>
<key>Type</key>
<string>PSGroupSpecifier</string>
<key>FooterText</key> # <= here is the change
<string>$keynum</string>
</dict>
EOD
print $outfh "\"$keynum\" = \"$str\";\n";
$keynum = $key.(++$cnt);
}
Here's the same solution that @JosephH provided 2 (without translations), but done in Python 1 for anyone who prefers python over perl
import os
import sys
import plistlib
from copy import deepcopy
os.chdir(sys.path[0])
plist = {'PreferenceSpecifiers': [], 'StringsTable': 'Acknowledgements'}
base_group = {'Type': 'PSGroupSpecifier', 'FooterText': '', 'Title': ''}
for filename in os.listdir("."):
if filename.endswith(".license"):
current_file = open(filename, 'r')
group = deepcopy(base_group)
title = filename.split(".license")[0]
group['Title'] = title
group['FooterText'] = current_file.read()
plist['PreferenceSpecifiers'].append(group)
plistlib.writePlist(
plist,
"../Settings.bundle/Acknowledgements.plist"
)
As an alternative, for those using CocoaPods, it 9 will generate an 'Acknowledgements' plist 8 for each target specified in your Podfile 7 which contains the License details for each 6 Pod used in that target (assuming details 5 have been specified in the Pod spec). The 4 property list file that can be added to 3 the iOS settings bundle.
There's also projects 2 under way to allow this data to be converted 1 and displayed within the app instead:
I thought I'd throw my iteration on Sean's 12 awesome python code in the mix. The main 11 difference is that it takes an input directory 10 and then recursively searches it for LICENSE 9 files. It derives the title value from the 8 parent directory of the LICENSE file, so 7 it plays well with cocoapods.
The motivation 6 was to create a build script to automatically 5 keep the legal section of my app up to date 4 as I add or remove pods. It also does some 3 other things like remove forced newlines 2 from licenses so the paragraphs look a bit 1 better on the devices.
https://github.com/carloe/LicenseGenerator-iOS
I made a script in Ruby inspiered by @JosephH 5 script. This version will, in my own opinion, better 4 represent the individual open source projects.
Wisit 3 iOS-AcknowledgementGenerator to download the script and sample project.
This 2 is what acknowledgements will look like 1 in your App:
This is an addendum to JosephH's answer. (I 7 don't have the rep to comment)
I had to move 6
<key>StringsTable</key>
<string>Acknowledgements</string>
down to above the last </dict>
in the Perl script.
Before 5 this modification, the Acknowledgements 4 Section in the App was empty and XCode couldn't 3 read the resulting Acknowledgements.plist. ( "The 2 data couldn’t be read because it isn’t in 1 the correct format.")
(XCode 6.3.2 iOS 8.3)
The Python script from Sean in this thread 2 works. But there a couple of basic things 1 to know.
- in Xcode, right click on the top of the Project Navigator tree, on the name of your project, and add a New Group. This puts a new folder in your project.
- Add Sean's script there and make sure to save it as: Acknowledgements.py.
- Make sure you have Python installed on your system. I'm using a Mac.
- Add a first license file to the folder you created in 1. Make it simple like just having one word in the file, say: Testing. Save it in the folder as Test1.license.
- Set up your Settings.bundle as per JosephH above.
- Use your Terminal app to CD to the folder you created in 1.
- Run the script. Type: python Acknowledgements.py. If you get no errors it will return right back to the Terminal prompt. Do all of this before adding any run script to the Build.
- Build and run your app.
- Double tap on the iPhone home button and kill Settings. It doesn't often pick up the Settings change for your app until Settings restarts.
- After restarting Settings, go to your app and look to see if it worked.
- If that all worked, slowly add more license files but run the script each time. You can get errors running the script because of certain characters in the file so the easy way to debug is to add a file, run the script, see if it worked and proceed. Else, edit any special characters out of the .license file.
- I did not get the Run Build Script work per the instructions above. But this process works fine if you are not changing the .license files that often.
Ack Ack: Acknowledgement Plist Generator
A while back I've created a Python script 6 that scans for license files and creates 5 a nice Acknowledgements plist that you can 4 use in your Settings.plist. It does a lot 3 of the work for you.
https://github.com/Building42/AckAck
Features
- Detects Carthage and CocoaPods folders
- Detects existing plists for custom licenses
- Cleans up the license texts by removing unnecessary new lines and line breaks
- Provides many customization options (see
--help
for details) - Supports both Python v2 and v3
Install
wget https://raw.githubusercontent.com/Building42/AckAck/master/ackack.py
chmod +x ackack.py
Run
./ackack.py
Screenshot
If you have suggestions 2 for improvements, feel free to post an issue 1 or pull request on GitHub!
Aknowlist is a strong CocoaPod candidate that is 6 actively maintained at the time of this 5 writing. It automates this licensing if 4 you are okay with housing the licenses in 3 your app rather than the settings bundle. It 2 worked great for the project I was working 1 on.
I had to modify sean's script for modern 1 python3:
import os
import sys
import plistlib
from copy import deepcopy
os.chdir(sys.path[0])
plist = {'PreferenceSpecifiers': [], 'StringsTable': 'Acknowledgements'}
base_group = {'Type': 'PSGroupSpecifier', 'FooterText': '', 'Title': ''}
for filename in os.listdir("."):
if filename.endswith(".license"):
with open(filename, 'r') as current_file:
group = deepcopy(base_group)
title = filename.split(".license")[0]
group['Title'] = title
group['FooterText'] = current_file.read()
plist['PreferenceSpecifiers'].append(group)
with open("Acknowledgements.plist", "wb") as f:
plistlib.dump(plist, f)
More Related questions
We use cookies to improve the performance of the site. By staying on our site, you agree to the terms of use of cookies.