Reputation: 37505
My iOS application uses a number of third party components licensed under Apache 2.0 and similar licenses, which requires me to include various bits of text, this kind of thing:
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
There seems to be a reasonable precedent for putting this information under a 'License' subentry in settings bundle (on the ipad facebook, pages, keynote, numbers and wikipanion all seem to do this).
I'm struggling a bit to actually achieve the same though; I seem to need to split the text up line by line and enter into xcode a line at a time (and xcode4 seems to have a crashing problem when editing the plists).
It seems like the kind of thing that there's almost certainly a somewhere script to do, or some simple way to do it that I've missed.
Upvotes: 127
Views: 50064
Reputation: 329
Wait, license notation is not a setting.
Edit: I think license notice is not a setting. I think it is irrational to expect users who want to check the license notice to open the settings app. Therefore, I thought we should create a page for the license notice in the appropriate place in the app.
Upvotes: -1
Reputation: 11143
I had to modify sean's script for modern 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)
Upvotes: 0
Reputation: 41
Aknowlist is a strong CocoaPod candidate that is actively maintained at the time of this writing. It automates this licensing if you are okay with housing the licenses in your app rather than the settings bundle. It worked great for the project I was working on.
Upvotes: 0
Reputation: 19263
Ack Ack: Acknowledgement Plist Generator
A while back I've created a Python script that scans for license files and creates a nice Acknowledgements plist that you can use in your Settings.plist. It does a lot of the work for you.
https://github.com/Building42/AckAck
Features
--help
for details)Install
wget https://raw.githubusercontent.com/Building42/AckAck/master/ackack.py
chmod +x ackack.py
Run
./ackack.py
Screenshot
If you have suggestions for improvements, feel free to post an issue or pull request on GitHub!
Upvotes: 1
Reputation: 719
The Python script from Sean in this thread works. But there a couple of basic things to know.
Upvotes: 2
Reputation: 37505
I think I've now managed to solve all the problems I was running into.
I've got a convenience script I use to help generate the .plist and .strings file, shown below.
To use it:
Here's 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);
If you haven't created a Settings.bundle, go to File --> New --> New File...
Under the Resource section, find the Settings Bundle. Use the default name and save it to the root of your project.
Expand the Settings.bundle
group and select Root.plist
. You will need to add a new section where its key will be Preference Items
of type Array
. Add the following information:
The Filename
key points to the plist that was created by this script. You can change the title
to what ever you want.
Also, if you want this script to run whenever you build your project, you can add a build phase to your target:
cd $SRCROOT/licenses
($SRCROOT
points to the root of your project)./yourScriptName.pl
After you have finished that, you can drag the Run Script
build phase sooner in the build process. You'll want to move it up before Compile Sources
so that the updates to your Settings Bundle get compiled and copied over.
Update for iOS 7: iOS 7 seems to handle the "Title" key different and is messing up the rendered text. To fix that the generated Acknowledgements.plist needs to use the "FooterText" key instead 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);
}
Upvotes: 199
Reputation: 1540
I thought I'd throw my iteration on Sean's awesome python code in the mix. The main difference is that it takes an input directory and then recursively searches it for LICENSE files. It derives the title value from the parent directory of the LICENSE file, so it plays well with cocoapods.
The motivation was to create a build script to automatically keep the legal section of my app up to date as I add or remove pods. It also does some other things like remove forced newlines from licenses so the paragraphs look a bit better on the devices.
https://github.com/carloe/LicenseGenerator-iOS
Upvotes: 15
Reputation: 53
This is an addendum to JosephH's answer. (I don't have the rep to comment)
I had to move
<key>StringsTable</key>
<string>Acknowledgements</string>
down to above the last </dict>
in the Perl script.
Before this modification, the Acknowledgements Section in the App was empty and XCode couldn't read the resulting Acknowledgements.plist. ( "The data couldn’t be read because it isn’t in the correct format.")
(XCode 6.3.2 iOS 8.3)
Upvotes: 2
Reputation: 37505
As an alternative, for those using CocoaPods, it will generate an 'Acknowledgements' plist for each target specified in your Podfile which contains the License details for each Pod used in that target (assuming details have been specified in the Pod spec). The property list file that can be added to the iOS settings bundle.
There's also projects under way to allow this data to be converted and displayed within the app instead:
https://github.com/CocoaPods/cocoapods-install-metadata
https://github.com/cocoapods/CPDAcknowledgements
Upvotes: 16
Reputation: 268
I made a script in Ruby inspiered by @JosephH script. This version will, in my own opinion, better represent the individual open source projects.
Wisit iOS-AcknowledgementGenerator to download the script and sample project.
This is what acknowledgements will look like in your App:
Upvotes: 8
Reputation: 781
Here's the same solution that @JosephH provided (without translations), but done in Python 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"
)
Upvotes: 37