简体   繁体   English

将许可证部分添加到 iOS 设置包的最佳方法

[英]best way to add license section to iOS settings bundle

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:我的 iOS 应用程序使用了一些在 Apache 2.0 和类似许可证下获得许可的第三方组件,这需要我包含各种文本,例如:

* 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).将此信息放在设置包中的“许可证”子条目下似乎有一个合理的先例(在 ipad facebook 上,页面、主题演讲、数字和 wikipanion 似乎都这样做)。

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).我似乎需要逐行拆分文本并一次输入 xcode 一行(并且 xcode4 在编辑 plist 时似乎有崩溃问题)。

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.看起来几乎肯定有某个地方的脚本可以做,或者我错过了一些简单的方法。

I think I've now managed to solve all the 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). 似乎最好使用组元素标题来保存许可证(这是Apple在iWork应用程序中所做的)。 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) 您可以通过包含文字回车(即,也称为^ M,\\ r或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 script I use to help generate the .plist and .strings file, shown below. 我有一个方便脚本,用于帮助生成.plist和.strings文件,如下所示。

To use it: 要使用它:

  1. Create a 'licenses' directory under your project 在项目下创建“许可证”目录
  2. Put script into that directory 将脚本放入该目录
  3. Put each license into that directory, one per file, with filenames that end .license 将每个许可证放入该目录,每个文件一个,文件名以.license结尾
  4. 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 每个段落之间应该有一个空行
  5. Change to licenses directory & run the script 切换到许可证目录并运行脚本
  6. Edit your settings bundle Root.plist to include a child section called 'Acknowledgements' 编辑您的设置捆绑Root.plist以包含名为“Acknowledments”的子部分

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);

Setting up your Settings.bundle 设置您的Settings.bundle

If you haven't created a Settings.bundle, go to File --> New --> New File... 如果您尚未创建Settings.bundle,请转到文件 - >新建 - >新建文件...

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 . 展开Settings.bundle组并选择Root.plist You will need to add a new section where its key will be Preference Items of type Array . 您需要添加一个新的部分,其中的键将是Array类型的Preference Items Add the following information: 添加以下信息:

在此输入图像描述

The Filename key points to the plist that was created by this script. Filename键指向此脚本创建的plist。 You can change the title to what ever you want. 您可以将title更改为您想要的内容。

Execute Script At Build Time 在构建时执行脚本

Also, if you want this script to run whenever you build your project, you can add a build phase to your target: 此外,如果您希望在构建项目时运行此脚本,则可以向目标添加构建阶段:

  1. Go to your project file 转到您的项目文件
  2. Select the target 选择目标
  3. Click the Build Phases tab 单击“构建阶段”选项卡
  4. In the lower right corner of that pane, click on 'Add Build Phase' 在该窗格的右下角,单击“添加构建阶段”
  5. Select 'Add Run Script' 选择“添加运行脚本”
  6. Drag and drop your perl script into the section for your script. 将perl脚本拖放到脚本部分。 Modify to look something like this: 修改看起来像这样:
  1. cd $SRCROOT/licenses ( $SRCROOT points to the root of your project) cd $SRCROOT/licenses$SRCROOT指向项目的根目录)
  2. ./yourScriptName.pl

After you have finished that, you can drag the Run Script build phase sooner in the build process. 完成后,您可以在构建过程中更快地拖动“ Run Script构建阶段。 You'll want to move it up before Compile Sources so that the updates to your Settings Bundle get compiled and copied over. 您需要在Compile Sources之前将其移动,以便编辑和复制设置包的更新。

Update for iOS 7: iOS 7 seems to handle the "Title" key different and is messing up the rendered text. iOS 7的更新: iOS 7似乎处理不同的“标题”键并且正在弄乱渲染的文本。 To fix that the generated Acknowledgements.plist needs to use the "FooterText" key instead of "Title". 要解决这个问题,生成的Acknowledgements.plist需要使用“FooterText”键而不是“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 (without translations), but done in Python for anyone who prefers python over perl 这是@JosephH提供的相同解决方案(没有翻译),但是在Python中为任何喜欢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 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). 作为替代方案,对于那些使用CocoaPods的人,它将为Podfile中指定的每个目标生成一个“Acknowledgements”plist,其中包含该目标中使用的每个Pod的许可证详细信息(假设已在Pod规范中指定了详细信息)。 The property list file that can be added to the iOS settings bundle. 可以添加到iOS设置包的属性列表文件。

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/cocoapods-install-metadata

https://github.com/cocoapods/CPDAcknowledgements https://github.com/cocoapods/CPDAcknowledgements

I thought I'd throw my iteration on Sean's awesome python code in the mix. 我以为我会把我的迭代扔在Sean的混合中很棒的python代码上。 The main difference is that it takes an input directory and then recursively searches it for LICENSE files. 它的主要区别在于它需要一个输入目录,然后以递归方式搜索它以获取LICENSE文件。 It derives the title value from the parent directory of the LICENSE file, so it plays well with cocoapods. 它从LICENSE文件的父目录派生标题值,因此它可以很好地与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. 我的动机是创建一个构建脚本,以便在添加或删除pod时自动保持我的应用程序的合法部分是最新的。 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 https://github.com/carloe/LicenseGenerator-iOS

在此输入图像描述

I made a script in Ruby inspiered by @JosephH script. 我在Ruby编写了一个由@JosephH脚本激发的脚本。 This version will, in my own opinion, better represent the individual open source projects. 在我看来,这个版本将更好地代表各个开源项目。

Wisit iOS-AcknowledgementGenerator to download the script and sample project. Wisit iOS-AcknowledgementGenerator下载脚本和示例项目。

This is what acknowledgements will look like in your App: 这是您的应用程序中的确认:

Settings.appSettings.bundle致谢在此输入图像描述

This is an addendum to JosephH's answer. 这是JosephH回答的补遗。 (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. 我不得不将<key>StringsTable</key> <string>Acknowledgements</string>向下移动到Perl脚本中的最后一个</dict>之上。

Before this modification, the Acknowledgements Section in the App was empty and XCode couldn't read the resulting Acknowledgements.plist. 在此修改之前,应用程序中的Acknowledgements部分为空,XCode无法读取生成的Acknowledgements.plist。 ( "The data couldn't be read because it isn't in the correct format.") (“无法读取数据,因为格式不正确。”)

(XCode 6.3.2 iOS 8.3) (XCode 6.3.2 iOS 8.3)

The Python script from Sean in this thread works. Sean在这个线程中的Python脚本有效。 But there a couple of basic things to know. 但有一些基本的事情要知道。

  1. in Xcode, right click on the top of the Project Navigator tree, on the name of your project, and add a New Group. 在Xcode中,右键单击Project Navigator树的顶部,在项目名称上,然后添加一个New Group。 This puts a new folder in your project. 这会在项目中放置一个新文件夹。
  2. Add Sean's script there and make sure to save it as: Acknowledgements.py. 在那里添加Sean的脚本,并确保将其保存为:Acknowledgements.py。
  3. Make sure you have Python installed on your system. 确保在系统上安装了Python。 I'm using a Mac. 我正在使用Mac。
  4. 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. 将第一个许可文件添加到您在1中创建的文件夹中。简单地说,只需在文件中包含一个单词,即:测试。 Save it in the folder as Test1.license. 将其作为Test1.license保存在文件夹中。
  5. Set up your Settings.bundle as per JosephH above. 按照上面的JosephH设置您的Settings.bundle。
  6. Use your Terminal app to CD to the folder you created in 1. 使用终端应用程序将CD刻录到您在1中创建的文件夹。
  7. Run the script. 运行脚本。 Type: python Acknowledgements.py. 键入: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之前执行所有这些操作。
  8. Build and run your app. 构建并运行您的应用程序。
  9. Double tap on the iPhone home button and kill Settings. 双击iPhone主页按钮并终止设置。 It doesn't often pick up the Settings change for your app until Settings restarts. 在设置重新启动之前,它通常不会为您的应用选择设置更改。
  10. After restarting Settings, go to your app and look to see if it worked. 重新启动设置后,转到您的应用程序,看看它是否有效。
  11. 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. 否则,编辑.license文件中的任何特殊字符。
  12. I did not get the Run Build Script work per the instructions above. 我没有按照上面的说明运行Run Build Script。 But this process works fine if you are not changing the .license files that often. 但是,如果您不经常更改.license文件,则此过程可以正常工作。

Ack Ack: Acknowledgement Plist Generator Ack Ack:确认Plist生成器
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. 前段时间我创建了一个Python脚本,用于扫描许可证文件并创建一个很好的Acknowledments plist,您可以在Settings.plist中使用它。 It does a lot of the work for you. 它为你做了很多工作。

https://github.com/Building42/AckAck https://github.com/Building42/AckAck

Features 特征

  • Detects Carthage and CocoaPods folders 检测Carthage和CocoaPods文件夹
  • Detects existing plists for custom licenses 检测现有plist以获取自定义许可证
  • Cleans up the license texts by removing unnecessary new lines and line breaks 通过删除不必要的新行和换行符来清理许可证文本
  • Provides many customization options (see --help for details) 提供许多自定义选项(有关详细信息,请参阅--help
  • Supports both Python v2 and v3 支持Python v2和v3

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! 如果您有改进建议,请随时在GitHub上发布问题或提出请求!

Aknowlist is a strong CocoaPod candidate that is actively maintained at the time of this writing. Aknowlist是一个强大的 CocoaPod 候选者,在撰写本文时正在积极维护。 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.它对我正在从事的项目非常有用。

I had to modify sean's script for modern python3:我不得不为现代 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)

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.因此,我认为我们应该在应用程序的适当位置为许可声明创建一个页面。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM