developer tip

내 애플리케이션의 설정 번들에 애플리케이션 버전 개정을 표시하려면 어떻게해야합니까?

optionbox 2020. 9. 23. 07:33
반응형

내 애플리케이션의 설정 번들에 애플리케이션 버전 개정을 표시하려면 어떻게해야합니까?


내 애플리케이션의 설정 번들에 1.0.1 (r1243)과 같은 애플리케이션 버전과 내부 개정을 포함하고 싶습니다.

Root.plist 파일에는 다음과 같은 조각이 포함되어 있습니다.

     <dict>
        <key>Type</key>
        <string>PSTitleValueSpecifier</string>
        <key>Title</key>
        <string>Version</string>
        <key>Key</key>
        <string>version_preference</string>
        <key>DefaultValue</key>
        <string>VersionValue</string>
        <key>Values</key>
        <array>
            <string>VersionValue</string>
        </array>
        <key>Titles</key>
        <array>
            <string>VersionValue</string>
        </array>
    </dict>

빌드 할 때 "VersionValue"문자열을 바꾸고 싶습니다.

내 저장소에서 버전 번호를 추출 할 수있는 스크립트가 있습니다. 필요한 것은 빌드시 Root.plist 파일을 처리 (사전 처리)하고 소스 파일에 영향을주지 않고 개정 번호를 바꾸는 방법입니다.


이전 답변보다 훨씬 간단 할 수있는 또 다른 솔루션이 있습니다. Apple은 대부분의 설치 프로그램에 PlistBuddy 라는 명령 줄 도구를 번들로 제공 하며이 도구 를 Leopard의 /usr/libexec/PlistBuddy.

VersionValue추출 된 버전 값이 있다고 가정하고을 바꾸고 싶으므로 다음 $newVersion명령을 사용할 수 있습니다.

/usr/libexec/PlistBuddy -c "Set :VersionValue $newVersion" /path/to/Root.plist

sed 또는 정규식을 조작 할 필요가 없습니다.이 접근 방식은 매우 간단합니다. 자세한 지침 매뉴얼 페이지참조하십시오 . PlistBuddy를 사용하여 속성 목록의 항목을 추가, 제거 또는 수정할 수 있습니다. 예를 들어, 내 친구가 PlistBuddy를 사용하여 Xcode에서 빌드 번호 를 늘리는 것에 대해 블로그 를 작성했습니다.

참고 : plist에 대한 경로 만 제공하면 PlistBuddy는 대화 형 모드로 전환되므로 변경 사항 저장을 결정하기 전에 여러 명령을 실행할 수 있습니다. 빌드 스크립트에서 작업하기 전에이 작업을 수행하는 것이 좋습니다.


내 게으른 사람의 해결책은 내 애플리케이션 코드에서 버전 번호를 업데이트하는 것이 었습니다. Root.plist에 기본 (또는 공백) 값이있을 수 있으며 시작 코드의 어딘가에 있습니다.

NSString *version = [[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"];
[[NSUserDefaults standardUserDefaults] setObject:version forKey:@"version_preference"];

유일한 문제는 업데이트 된 버전이 설정 패널에 표시 되려면 앱을 한 번 이상 실행해야한다는 것입니다.

예를 들어 앱이 실행 된 횟수에 대한 카운터 또는 기타 흥미로운 정보를 업데이트 할 수 있습니다.


@Quinn의 답변에 따라 여기에 전체 프로세스와 작업 코드가 있습니다.

  • 앱에 설정 번들을 추가합니다. 이름을 바꾸지 마십시오.
  • 텍스트 편집기에서 Settings.bundle / Root.plist를 엽니 다.

내용을 다음으로 바꿉니다.

<?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>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Title</key>
            <string>About</string>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <string>DummyVersion</string>
            <key>Key</key>
            <string>version_preference</string>
            <key>Title</key>
            <string>Version</string>
            <key>Type</key>
            <string>PSTitleValueSpecifier</string>
        </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
</dict>
</plist>
  • 크리에이트 스크립트 실행 빌드 단계는 이후로 이동 복사 번들 리소스 단계입니다. 이 코드를 추가하십시오.

    cd "${BUILT_PRODUCTS_DIR}"
    buildVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}" )
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $buildVersion" "${WRAPPER_NAME}/Settings.bundle/Root.plist"
    
  • MyAppName을 실제 앱 이름으로 바꾸고 PreferenceSpecifiers 뒤의 1을 설정에서 버전 항목의 인덱스로 바꿉니다. 위의 Root.plist 예제는 인덱스 1에 있습니다.


Ben Clayton의 plist https://stackoverflow.com/a/12842530/338986 사용

Run script뒤에 다음 스 니펫으로 추가하십시오 Copy Bundle Resources.

version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:1:DefaultValue $version ($build)" "$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist"

추가 CFBundleVersionCFBundleShortVersionString. 다음과 같은 버전을 내 보냅니다.

$CODESIGNING_FOLDER_PATH/Settings.bundle/Root.plist대신에 편지를 쓰면 $SRCROOT몇 가지 이점이 있습니다.

  1. 저장소의 작업 복사본에서 파일을 수정하지 않습니다.
  2. Settings.bundle에서 경로를 대소 문자로 지정할 필요가 없습니다 $SRCROOT. 경로는 다를 수 있습니다.

Xcode 7.3.1에서 테스트


여기 예제를 기반으로 설정 번들 버전 번호를 자동으로 업데이트하는 데 사용하는 스크립트는 다음과 같습니다.

#! /usr/bin/env python
import os
from AppKit import NSMutableDictionary

settings_file_path = 'Settings.bundle/Root.plist' # the relative path from the project folder to your settings bundle
settings_key = 'version_preference' # the key of your settings version

# these are used for testing only
info_path = '/Users/mrwalker/developer/My_App/Info.plist'
settings_path = '/Users/mrwalker/developer/My_App/Settings.bundle/Root.plist'

# these environment variables are set in the XCode build phase
if 'PRODUCT_SETTINGS_PATH' in os.environ.keys():
    info_path = os.environ.get('PRODUCT_SETTINGS_PATH')

if 'PROJECT_DIR' in os.environ.keys():
    settings_path = os.path.join(os.environ.get('PROJECT_DIR'), settings_file_path)

# reading info.plist file
project_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(info_path)
project_bundle_version = project_plist['CFBundleVersion']

# print 'project_bundle_version: '+project_bundle_version

# reading settings plist
settings_plist = NSMutableDictionary.dictionaryWithContentsOfFile_(settings_path)
  for dictionary in settings_plist['PreferenceSpecifiers']:
    if 'Key' in dictionary and dictionary['Key'] == settings_key:
        dictionary['DefaultValue'] = project_bundle_version

# print repr(settings_plist)
settings_plist.writeToFile_atomically_(settings_path, True)

Settings.bundle에있는 Root.plist는 다음과 같습니다.

<?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>PreferenceSpecifiers</key>
    <array>
        <dict>
            <key>Title</key>
            <string>About</string>
            <key>Type</key>
            <string>PSGroupSpecifier</string>
        </dict>
        <dict>
            <key>DefaultValue</key>
            <string>1.0.0.0</string>
            <key>Key</key>
            <string>version_preference</string>
            <key>Title</key>
            <string>Version</string>
            <key>Type</key>
            <string>PSTitleValueSpecifier</string>
        </dict>
    </array>
    <key>StringsTable</key>
    <string>Root</string>
</dict>
</plist>

다른 답변은 한 가지 이유로 제대로 작동하지 않습니다. 실행 스크립트 빌드 단계는 설정 번들이 패키지화 될 때까지 실행되지 않습니다. 따라서 Info.plist 버전이 2.0.11이고이를 2.0.12로 업데이트 한 다음 프로젝트를 빌드 / 보관하면 설정 번들은 여전히 ​​2.0.11로 표시됩니다. 설정 번들 Root.plist를 열면 빌드 프로세스가 끝날 때까지 버전 번호가 업데이트되지 않음을 알 수 있습니다. 프로젝트를 다시 빌드하여 설정 번들을 올바르게 업데이트하거나 대신 빌드 전 단계에 스크립트를 추가 할 수 있습니다.

  • XCode에서 프로젝트 대상의 구성표를 편집하십시오.
  • BUILD 구성표에서 공개 화살표를 클릭하십시오.
  • 그런 다음 "사전 조치"항목을 클릭하십시오.
  • 더하기 기호를 클릭하고 "New Run Script Action"을 선택합니다.
  • Set the shell value to /bin/sh
  • Set "Provide build settings from" to your project target
  • Add your script to the text area. The following script worked for me. You may need to modify the paths to match your project setup:

    versionString=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${PROJECT_DIR}/${INFOPLIST_FILE}")

    /usr/libexec/PlistBuddy "$SRCROOT/Settings.bundle/Root.plist" -c "set PreferenceSpecifiers:0:DefaultValue $versionString"

This will correctly run the script BEFORE the Settings bundle is packaged during the build/archive process. If you open the Settings bundle Root.plist and build/archive your project, you will now see the version number is updated at the beginning of the build process and your Settings bundle will display the correct version.


I managed to do what I wanted by using the pListcompiler (http://sourceforge.net/projects/plistcompiler) open source porject.

  1. Using this compiler you can write the property file in a .plc file using the following format:

    plist {
        dictionary {
            key "StringsTable" value string "Root"
            key "PreferenceSpecifiers" value array [
                dictionary {
                    key "Type" value string "PSGroupSpecifier"
                    key "Title" value string "AboutSection"
                }
                dictionary {
                    key "Type" value string "PSTitleValueSpecifier"
                    key "Title" value string "Version"
                    key "Key" value string "version"
                    key "DefaultValue" value string "VersionValue"
                    key "Values" value array [
                        string "VersionValue"
                    ]
                    key "Titles" value array [
                        string "r" kRevisionNumber
                    ]
                }
            ]
        }
    }
    
  2. I had a custom run script build phase that was extracting my repository revision to .h file as described by brad-larson here.

  3. The plc file can contain preprocessor directives, like #define, #message, #if, #elif, #include, #warning, #ifdef, #else, #pragma, #error, #ifndef, #endif, xcode environment variables. So I was able to reference the variable kRevisionNumber by adding the following directive

    #include "Revision.h"
    
  4. I also added a custom script build phase to my xcode target to run the plcompiler every time the project is beeing build

    /usr/local/plistcompiler0.6/plcompile -dest Settings.bundle -o Root.plist Settings.plc
    

And that was it!


My working Example based on @Ben Clayton answer and the comments of @Luis Ascorbe and @Vahid Amiri:

Note: This approach modifies the Settings.bundle/Root.plist file in working copy of repository

  1. Add a settings bundle to your project root. Don't rename it
  2. Open Settings.bundle/Root.plist as SourceCode

    Replace the contents with:

    <?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>PreferenceSpecifiers</key>
        <array>
            <dict>
                <key>DefaultValue</key>
                <string></string>
                <key>Key</key>
                <string>version_preference</string>
                <key>Title</key>
                <string>Version</string>
                <key>Type</key>
                <string>PSTitleValueSpecifier</string>
            </dict>
        </array>
        <key>StringsTable</key>
        <string>Root</string>
    </dict>
    </plist>
    
  3. Add the following script to the Build, Pre-actions section of the project (target) scheme

    version=$(/usr/libexec/PlistBuddy -c "Print CFBundleShortVersionString" "$PROJECT_DIR/$INFOPLIST_FILE")
    build=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "$PROJECT_DIR/$INFOPLIST_FILE")
    
    /usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:0:DefaultValue $version ($build)" "${SRCROOT}/Settings.bundle/Root.plist"
    
  4. Build and Run the current scheme


I believe you can do this using a way that's similar to what I describe in this answer (based on this post).

First, you can make VersionValue a variable within Xcode by renaming it to ${VERSIONVALUE}. Create a file named versionvalue.xcconfig and add it to your project. Go to your application target and go to the Build settings for that target. I believe that you need to add VERSIONVALUE as a user-defined build setting. In the lower-right-corner of that window, change the Based On value to "versionvalue".

Finally, go to your target and create a Run Script build phase. Inspect that Run Script phase and paste in your script within the Script text field. For example, my script to tag my BUILD_NUMBER setting with the current Subversion build is as follows:

REV=`/usr/bin/svnversion -nc ${PROJECT_DIR} | /usr/bin/sed -e 's/^[^:]*://;s/[A-Za-z]//'`
echo "BUILD_NUMBER = $REV" > ${PROJECT_DIR}/buildnumber.xcconfig

This should do the trick of replacing the variable when these values change within your project.


Above answers did not work for me hence I created my custom script.

This dynamically updates the entry from Root.plist

Use run script below. W ill work for sure verified in xcode 10.3.

"var buildVersion" is the version to be displayed in title.

And identifier name is "var version" below for title in settings.bundle Root.plist

cd "${BUILT_PRODUCTS_DIR}"

#set version name to your title identifier's string from settings.bundle
var version = "Version"

#this will be the text displayed in title
longVersion=$(/usr/libexec/PlistBuddy -c "Print CFBundleVersion" "${INFOPLIST_PATH}")
shortVersion=$(/usr/libexec/PlistBuddy -c "Print :CFBundleShortVersionString" ${TARGET_BUILD_DIR}/${INFOPLIST_PATH})
buildVersion="$shortVersion.$longVersion"

path="${WRAPPER_NAME}/Settings.bundle/Root.plist"

settingsCnt=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:" ${path} | grep "Dict"|wc -l`

for (( idx=0; idx<$settingsCnt; idx++ ))
do
#echo "Welcome $idx times"
val=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:Key" ${path}`
#echo $val

#if ( "$val" == "Version" )
if [ $val == "Version" ]
then
#echo "the index of the entry whose 'Key' is 'version' is $idx."

# now set it
/usr/libexec/PlistBuddy -c "Set PreferenceSpecifiers:${idx}:DefaultValue $buildVersion" $path

# just to be sure that it worked
ver=`/usr/libexec/PlistBuddy -c "Print PreferenceSpecifiers:${idx}:DefaultValue" $path`
#echo 'PreferenceSpecifiers:$idx:DefaultValue set to: ' $ver

fi

done

Example entry in Root.plist

    <dict>
        <key>Type</key>
        <string>PSTitleValueSpecifier</string>
        <key>Title</key>
        <string>Version</string>
        <key>DefaultValue</key>
        <string>We Rock</string>
        <key>Key</key>
        <string>Version</string>
    </dict>

Working sample Root.plist entry

참고URL : https://stackoverflow.com/questions/877128/how-can-i-display-the-application-version-revision-in-my-applications-settings

반응형