Skip to content

2016

Launching RancherOS on AWS EC2

RancherOS is a Linux distribution designed for running Docker containers. While there is an AMI (Amazon Machine Image) available in the AWS Marketplace, setting up the security group and other configurations can be tricky. This guide serves as the missing manual.

1. Launch an Instance with the Rancher AMI

Assuming you already have a .pem key, launch an instance and select the Rancher AMI.

2. Connect to Your Instance

Open a terminal and connect to your instance. Note that you should use rancher as the user, rather than root:

ssh -i "XXX.pem" rancher@ec2-XX-XXX-XX-XX.ap-southeast-1.compute.amazonaws.com
3. Verify the Rancher Server

The Rancher server should already be running. You can check by executing:

docker ps

If it's not running, download and start the server using Docker:

docker run -d -p 8080:8080 rancher/server
4. Configure Security Groups

Navigate to the Security Group tab in the AWS console and create a new one with inbound rules:

The rules should include:

  • Ports 22, 2376, and 8080/tcp for Docker Machine to provision hosts
  • Ports 500 and 4500/udp for the Rancher network
  • Ports 9345 and 9346/tcp for the UI
  • Port 80/tcp for the site you deploy
5. Assign the New Security Group

Select the instance, then navigate to Actions > Networking > Change Security Group. Check the new Security Group ID and assign it to your instance.

6. Access the Rancher UI

Open a browser and navigate to the Public DNS with port 8080, such as http://ec2-XX-XXX-XX-XX.ap-southeast-1.compute.amazonaws.com:8080.

You should see the Rancher UI:

7. Add Host Using AWS Credentials

To add a host with Amazon EC2, you'll need the Access Key and Secret Key. If you don’t have them, go to the AWS Console > IAM (Identity and Access Management) > Create New Users. Download the credentials.csv file.

Next, go to the Groups tab > Group Actions > Add Users to Group. Attach the policy by searching for "AmazonEC2FullAccess", check the box, and apply the changes.

8. Enter AWS Credentials in Rancher UI

Return to the Rancher UI and enter the newly generated Access Key and Secret Key from the credentials.csv file.

Finally, fill out the necessary information and you'll see your host up and running.

Postscript

To manage Docker's secret API keys, certificate files, and production configuration, you can try the beta Vault integration, depending on your specific needs.

在AWS EC2上啟動RancherOS

RancherOS是一種為運行Docker容器而設計的Linux發行版。雖然AWS Marketplace已經有可用的AMI(Amazon Machine Image),但設置安全組和其他配置可能會有些棘手。這份指南就是缺少的使用手冊。

1. 使用Rancher AMI啟動一個實例

假設你已經有一個 .pem密鑰,啟動一個實例並選擇Rancher AMI。

2. 連接到您的實例

打開終端並連接到您的實例。請注意,您應該使用rancher作為用戶,而不是root:

ssh -i "XXX.pem" rancher@ec2-XX-XXX-XX-XX.ap-southeast-1.compute.amazonaws.com
3. 驗證Rancher服務器

Rancher服務器應該已經在運行。你可以通過執行以下命令進行檢查:

docker ps

如果它沒有運行,可以使用Docker下載並啟動服務器:

docker run -d -p 8080:8080 rancher/server
4. 配置安全組

在AWS控制台中,轉到Security Group選項卡並創建一個包含入站規則的新組:

規則應包括:

  • 端口22、2376和8080/tcp 供Docker機器分配主機
  • 端口500和4500/udp 供Rancher網絡使用
  • 端口9345和9346/tcp 用於UI界面
  • 端口80/tcp 用於您部署的站點
5. 分配新的安全組

選擇實例,然後導航到Actions > Networking > Change Security Group。檢查新的安全組ID並將其分配給您的實例。

6. 訪問Rancher UI

打開一個瀏覽器並轉到公共DNS的8080端口,如 http://ec2-XX-XXX-XX-XX.ap-southeast-1.compute.amazonaws.com:8080

您應該會看到Rancher UI:

7. 使用AWS憑證添加主機

要使用Amazon EC2添加一個主機,您需要Access Key和Secret Key。如果您沒有它們,請前往AWS Console > IAM (Identity and Access Management) > Create New Users。下載credentials.csv文件。

接下來,前往Groups選項卡 > Group Actions > Add Users to Group。通過搜索"AmazonEC2FullAccess"來附加策略,選中方框,並應用更改。

8. 在Rancher UI中輸入AWS憑證

返回到Rancher UI,並從credentials.csv文件中輸入新生成的Access Key和Secret Key。

最後,填寫所需的信息,您將看到您的主機正在運行。

附言

要管理Docker的秘密API鑰匙、證書文件和生產配置,您可以根據您的具體需求嘗試使用beta版的Vault集成。

Deploying a Java Spring Server with a Docker Container

In this guide, I'll show you how to deploy a Java Spring server using Docker. Below are the steps to follow:

1. Launch an Ubuntu Server

For this demo, let's assume you have launched a server running Ubuntu 14.04. Install Docker using the APT repository:

sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

Open /etc/apt/sources.list.d/docker.list with your favorite text editor and add the following line:

deb [https://apt.dockerproject.org/repo](https://apt.dockerproject.org/repo) ubuntu-trusty main

Proceed to install Docker on the server:

sudo apt-get update
sudo apt-get install docker-engine
sudo service docker start
2. Build the Docker Image

Log in to Docker Hub (https://hub.docker.com/) and create a new repository. Then, in your terminal, run:

docker login

Enter your username and password when prompted.

In your local development Java Spring folder, create a Dockerfile with the following content:

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD target/fleet-beacon*.jar app.jar
EXPOSE 8080
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java", "-jar", "/app.jar"]

To build the image, execute:

docker build -t username/repo-name .

Here, -t stands for "tag." Replace username and repo-name with your Docker Hub username and repository name. Also, don't forget the trailing dot.

Push the built image to your remote repository:

docker push username/repo-name
3. Pull the Docker Image

On your remote Ubuntu server, log in to Docker and pull the image:

docker pull username/repo-name

Run the container in the background:

docker run -d -p 8080:8080 username/repo-name

Here, -d means "detached," and -p specifies that all exposed ports (e.g., 8080) should be published to the host interfaces.

4. Set Up Nginx

Using the Vim editor, open /etc/nginx/sites-available/default and modify it as follows:

server {
  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  root /usr/share/nginx/html;
  index index.html index.htm;
  server_name localhost;

  location / {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass [http://localhost:8080/](http://localhost:8080/);
  }
}

Exit and save with :wq!.

That's it! Open a browser and navigate to your remote server's IP address; you should see the Java Spring page running smoothly.

5. Troubleshooting

If you encounter an issue with the Docker daemon connection, showing:

Cannot connect to the Docker daemon. Is the Docker daemon running on this host?

Run the following command:

eval $(docker-machine env default)

If you're testing locally and can't find your IP address, use this command to find it:

docker-machine ls

Feel free to leave a comment below if you encounter any other issues.

使用Docker容器部署Java Spring伺服器

在這份指南中,我將展示如何使用Docker部署Java Spring伺服器。請按照以下步驟操作:

1.啟動一個Ubuntu Server

對於這份演示,我們假設你已經啟動了一個運行Ubuntu 14.04的伺服器。使用APT資源庫安裝Docker:

sudo apt-get update
sudo apt-get install apt-transport-https ca-certificates
sudo apt-key adv --keyserver hkp://p80.pool.sks-keyservers.net:80 --recv-keys 58118E89F3A912897C070ADBF76221572C52609D

使用你最喜歡的文字編輯器打開/etc/apt/sources.list.d/docker.list,並添加以下行:

deb [https://apt.dockerproject.org/repo](https://apt.dockerproject.org/repo) ubuntu-trusty main

繼續在伺服器上安裝Docker:

sudo apt-get update
sudo apt-get install docker-engine
sudo service docker start
2.構建Docker映像

登入Docker Hub (https://hub.docker.com/),並創建新的儲存庫。然後,在你的終端機運行:

docker login

被提示時輸入您的用戶名和密碼。

在你的本地開發Java Spring資料夾,創建一個Dockerfile,內容如下:

FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD target/fleet-beacon*.jar app.jar
EXPOSE 8080
RUN sh -c 'touch /app.jar'
ENTRYPOINT ["java", "-jar", "/app.jar"]

要構建映像,執行:

docker build -t username/repo-name .

這裡,-t代表"tag"。將usernamerepo-name替換成你的Docker Hub用戶名和儲存庫名稱。也不要忘記最後的句點。

將構建的映像推送到您的遠程儲存庫:

docker push username/repo-name
3.拉取Docker映像

在您的遠程Ubuntu伺服器上,登入Docker並拉取映像:

docker pull username/repo-name

在後臺運行容器:

docker run -d -p 8080:8080 username/repo-name

這裡,-d表示"detached", -p指定所有暴露的端口(例如,8080)都應該發布到主機接口。

4.設置Nginx

使用Vim編輯器,打開/etc/nginx/sites-available/default並將其修改如下:

server {
  listen 80 default_server;
  listen [::]:80 default_server ipv6only=on;

  root /usr/share/nginx/html;
  index index.html index.htm;
  server_name localhost;

  location / {
    proxy_set_header X-Forwarded-Host $host;
    proxy_set_header X-Forwarded-Server $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_pass [http://localhost:8080/](http://localhost:8080/);
  }
}

退出並使用:wq!保存。

就這樣!打開瀏覽器,導航到你的遠程伺服器的IP地址;你應該能看到Java Spring頁面運行正常。

5.問題排查

如果你遇到Docker守護進程連接的問題,出現:

Cannot connect to the Docker daemon. Is the Docker daemon running on this host?

運行以下命令:

eval $(docker-machine env default)

如果你正在本地測試且找不到你的IP地址,用這個命令找到它:

docker-machine ls

如果你遇到任何其他問題,請隨時在下方留言。

Apple Push Notification with Java Spring Framework

I'm implementing a Java Spring Framework server that sends Apple Push Notifications to an iPhone using Swift. Here are the things you will need:

1. Account Setup

Assuming you already have an Apple developer account with certificates, log in to Apple Developer, go to the tab Identifiers and click "+" to add a new one. Fill in the prefix and suffix, then remember to check the box for “Push Notifications.”

Image1 Image2

Next, select Edit and scroll to the Push Notifications section. Here, you'll see the “Configurable” orange indicators. Create and download the Development SSL certificate using your CSR file. Double-click to run it and add it to your keychain.

Image3

Open Keychain Access, find the certificate, and export it as a .p12 file. You'll be prompted to enter a password—don't leave it blank. Otherwise, the Java Spring app may not be able to parse an empty string. Save this file for later use.

Image4

2. Xcode Setup

Create a new Xcode project, such as a Single View Application. In the Capabilities tab, enable “Push Notifications” and log in with your Apple ID.

Image5

In AppDelegate.swift, add a method to create an instance of settings, which will prompt the user for permission when the app launches:

func registerForPushNotifications(application: UIApplication) {
  let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: nil)
  application.registerUserNotificationSettings(notificationSettings)
}

Invoke this method when the application finishes launching:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  // Override point for customization after application launch.
  registerForPushNotifications(application)
  return true
}

In the same AppDelegate.swift file, add methods to handle the user's permission decision:

func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
  if notificationSettings.types != .None {
    application.registerForRemoteNotifications()
  }
}

If the registration is successful, add:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
  let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
  var tokenString = ""

  for i in 0..<deviceToken.length {
    tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
  }

  print("Device Token:", tokenString)
}

And for registration failure:

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
  print("Failed to register:", error)
}

To test, you'll need a physical device; a simulator won't work. If successful, you should see the device token in the console. Note this for later use.

Image6

3. Java Spring Server Setup

Create a Java Spring Framework server using your favorite IDE like NetBeans or IntelliJ. In this example, we are using a Maven build with a pom.xml file like this:

<!-- pom.xml content -->

We will utilize the notnoop library from the Maven Repository. Add this dependency to your pom.xml:

<dependency>
  <groupId>com.notnoop.apns</groupId>
  <artifactId>apns</artifactId>
  <version>1.0.0.Beta6</version>
</dependency>

When the server starts, it will look for the main class, for example, PushNotificationApplication.java:

// PushNotificationApplication.java content

For demonstration purposes, we will create a NotificationController.java:

// NotificationController.java content

Replace the placeholders in the code with your actual .p12 file path, password, and device token. If you're unsure about the file path, place the .p12 file at the same level as your /src folder, i.e., the root of the project folder.

Run the following commands to install and start the server:

mvn install
mvn spring-boot:run

Open your browser and navigate to http://localhost:8080/notification. You should receive a notification!

Image7

Feel free to reach out if you have any questions :)


Note: The content inside the code blocks (XML, Swift, and Java) was not changed. Make sure that the content is accurate and up-to-date.

使用Java Spring框架的蘋果推送通知

我正在實現一個使用Java Spring Framework伺服器,使用Swift向iPhone發送Apple推送通知。以下是你將需要的東西:

1. 設定帳戶

假設您已經有一個帶有證書的Apple開發者帳戶,登入 Apple Developer,前往 Identifiers 分頁並點擊"+" 新增一個。填寫前綴和後綴,然後記住勾選 "推送通知" 的箱子。

Image1 Image2

接下来,选择 編輯,滚到 推送通知部分。在这里,你会看到“能够配置”的橙色指示器。使用你的CSR文件创建并下载Development SSL证书。双击运行它,并将其添加到你的钥匙链。

Image3

开启 钥匙链访问,找到证书,并将其导出为 .p12 文件。你会被提示输入密码 - 不要将其留空。否则,Java Spring应用程序可能无法解析空字符串。将此文件保存以供以后使用。

Image4

2. Xcode 設置

建立一个新的Xcode项目,例如一个单视图应用。在功能分頁中,開啟“推送通知”並用你的Apple ID登入。

Image5

AppDelegate.swift 中,新增一個方法來建立一個設定的實例,這將在應用啟動時提示用戶許可:

func registerForPushNotifications(application: UIApplication) {
  let notificationSettings = UIUserNotificationSettings(forTypes: [.Badge, .Sound, .Alert], categories: nil)
  application.registerUserNotificationSettings(notificationSettings)
}

当应用完成启动时调用此方法:

func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
  // Override point for customization after application launch.
  registerForPushNotifications(application)
  return true
}

在同一個 AppDelegate.swift 文件中,新增方法以處理用戶的權限決定:

func application(application: UIApplication, didRegisterUserNotificationSettings notificationSettings: UIUserNotificationSettings) {
  if notificationSettings.types != .None {
    application.registerForRemoteNotifications()
  }
}

如果注册成功,新增:

func application(application: UIApplication, didRegisterForRemoteNotificationsWithDeviceToken deviceToken: NSData) {
  let tokenChars = UnsafePointer<CChar>(deviceToken.bytes)
  var tokenString = ""

  for i in 0..<deviceToken.length {
    tokenString += String(format: "%02.2hhx", arguments: [tokenChars[i]])
  }

  print("Device Token:", tokenString)
}

如果注册失败:

func application(application: UIApplication, didFailToRegisterForRemoteNotificationsWithError error: NSError) {
  print("Failed to register:", error)
}

測試時,您將需要一個實體設備;模擬器將無法使用。如果成功,您應該在控制台中看到設備令牌。记下这个供后来使用。

Image6

3. Java Spring 服务器设置

使用你喜欢的IDE(如NetBeans或IntelliJ)创建一个Java Spring Framework服务器。在这个例子中,我们正在使用一个配备pom.xml文件的Maven构建:

<!-- pom.xml content -->

我们将使用来自Maven Repository的 notnoop库。将此依赖项添加到你的 pom.xml:

<dependency>
  <groupId>com.notnoop.apns</groupId>
  <artifactId>apns</artifactId>
  <version>1.0.0.Beta6</version>
</dependency>

服务器启动时,它会寻找主类,例如 PushNotificationApplication.java

// PushNotificationApplication.java content

为了演示目的,我们将创建一个 NotificationController.java

// NotificationController.java content

用你真正的 .p12 文件路径,密码,和设备令牌替换代码中的占位符。如果您对文件路径不确定,将 .p12 文件放在 /src 文件夹的同一级别,即项目文件夹的根目录。

运行以下命令以安装并启动服务器:

mvn install
mvn spring-boot:run

打开你的浏览器并导航到 http://localhost:8080/notification。你应该收到通知!

Image7

如果你有任何疑問,隨時聯絡我 :)


注意:代码块 (XML, Swift, 和 Java) 内的内容未作更改。确保内容准确且最新。

Submitting a Unity 3D Game to the Mac App Store

After three months of weekend development, our Unity 3D game is ready to be released and deployed to the App Store. However, the process was far from straightforward. I spent an entire night figuring it out. After many trials and errors, I decided to document some of the key steps here:

1. Unity Build Settings

In Unity, go to "File" > "Build Settings" > "Platform: PC, Mac & Linux Standalone" > "Target Platform: Mac OS".

Click "Player Settings..." and configure the following options:

Default is Full Screen = true
Default is Native Resolution = true
Capture Single Screen = false
Display Resolution Dialog = false
Mac App Store Validation = true
2. Info.plist

In Finder, right-click on the game app and select 'Show Package Content'. Inside the Content folder, edit the Info.plist file. Ensure:

  1. CFBundleGetInfoString is a valid string.
  2. CFBundleIdentifier and CFBundleSignature have values that match the bundle id (explained later).
  3. CFBundleShortVersionString and CFBundleVersion are in x.x.x format, e.g., 1.0.0.
  4. Add a new <key>LSApplicationCategoryType</key> with value <string>public.app-category.games</string>.

Example shown below:

    <?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>
     <!-- ... your keys and values here ... -->
    </dict>
    </plist>
3. Entitlements

In your Build folder, create a file named GAMENAME.entitlements with a sandbox key, like this:

    <?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>com.apple.security.app-sandbox</key>
        <true/>
    </dict>
    </plist>
4. Apple Developer Account

Assuming you already have a paid Apple Developer account, visit Apple Developer Account. Then, go to Certificates and choose the dropdown with "OS X". Click the "+" button to create new certificates. You will need to complete the process twice to get a "Mac App Distribution" and a "Mac Installer Distribution" certificate. Save them to your keychain for later use.

Next, go to "Identifiers" and choose the "App IDs" tab. Create a Wildcard App ID, but make sure it matches the bundle ID values from the previous step. For example, mine is unity.victorleungtw.*

5. iTunes Connect

Log in to iTunes Connect, go to My Apps > "+" > "New Mac App", and fill in the required fields. Make sure the Bundle ID matches the one from the previous step. The Prefix field should be the game name, such as ufo in my case.

You'll also need to take screenshots and crop them to the correct sizes. Only the following sizes are allowed:

  • 1280 x 800 pixels
  • 1440 x 900 pixels
  • 2560 x 1600 pixels
  • 2880 x 1800 pixels
6. Application Loader

Download and install the latest Application Loader to submit the app. Complete the following steps:

Fix the content permissions via a terminal command:

    chmod -R a+xr "/path/to/GAMENAME.app"

Sign the app with the entitlements document created in step 3:

    codesign -f -s '3rd Party Mac Developer Application: DEVELOPER NAME' --entitlements "GAMENAME.entitlements" "/AppPath/GAMENAME.app"

You're likely to encounter the error:

    code object is not signed at all

This occurs because subcomponents are not signed. You could sign them individually, including libmono.0.dylib and libMonoPosixHelper.dylib, but an easier way is to use the deep-sign command like this:

    codesign -f -s '3rd Party Mac Developer Application: DEVELOPER NAME' --entitlements "GAMENAME.entitlements

" "/AppPath/GAMENAME.app" --deep

Next, build the .pkg file:

    productbuild --component GAMENAME.app /Applications --sign "3rd Party Mac Developer Installer: DEVELOPER NAME" GAMENAME.pkg

Remove any existing instances of the game app from your machine. Then, you can verify the install with:

    sudo installer -store -pkg GAMENAME.pkg -target /

Finally, open the Application Loader and choose 'Deliver Your App', selecting the GAMENAME.pkg. If everything goes well, the upload should succeed. Otherwise, address any specific errors accordingly. The process will take some time.

7. Select the Build

If you receive an email citing issues such as:

> **Invalid Signature** — The main app bundle game at path GAMENAME.app has the following signing errors: invalid Info.plist (the plist or signature has been modified) in architecture: i386.

It's likely that one of your subcomponents wasn't signed correctly. You may need to consult Apple's documentation for further guidance.

Otherwise, return to iTunes Connect, select the uploaded build, and change the status from "Preparing for Review" to "Waiting For Review" > "Review" > "Ready for Sale."

I hope this blog post is helpful and saves you some time! :)

將Unity 3D遊戲提交到Mac應用商店

經過三個月的週末開發,我們的Unity 3D遊戲已經準備好發布並部署到App Store。然而,這個過程並不直觀。我花了一整夜來解決它。經過許多嘗試和錯誤,我決定在這裡記錄一些關鍵的步驟:

![./2016-05-29.png]

1. Unity生成設置

在Unity中,齁到"檔案" > "建立設置" > "平台: PC, Mac與Linux獨立" > "目標平台: Mac OS"。

點擊"玩家設置...",並配置以下選項:

默認為全屏=真
默認是原生分辨率=真
抓取單一螢幕=假
顯示分辨率對話框=假
Mac應用商店驗證=真
2. Info.plist

在Finder中,右擊遊戲應用並選擇'顯示包內容'。在內容文件夾中,編輯Info.plist文件。確保:

  1. CFBundleGetInfoString是一個有效的字符串。
  2. CFBundleIdentifier和CFBundleSignature的值與bundle id(稍後解釋)匹配。
  3. CFBundleShortVersionString和CFBundleVersion的格式為x.x.x,例如1.0.0。
  4. 新增一個<key>LSApplicationCategoryType</key>,值為<string>public.app-category.games</string>

以下面的例子為例:

    <?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>
     <!-- ... your keys and values here ... -->
    </dict>
    </plist>
3. 授權資訊

在你的Build文件夾中,創建一個名為GAMENAME.entitlements的文件,添加一個sandbox鍵,如下所示:

    <?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>com.apple.security.app-sandbox</key>
        <true/>
    </dict>
    </plist>
4. Apple開發者帳戶

假設你已經有一個付費的Apple開發者帳戶,訪問 Apple Developer Account。然後,轉到證書並選擇"OS X"的下拉列表。點擊"+"按鈕創建新的證書。你需要完成兩次這個過程以獲取"Mac應用分發"和"Mac安裝程序分發"證書。將它們保存到你的鑰匙鏈以供日後使用。

然後,轉到"識別碼"並選擇"應用ID"標籤。創建一個萬用應用ID,但要確保它與前一步驟中的bundle ID值匹配。例如,我的是unity.victorleungtw.*

5. iTunes Connect

登錄到 iTunes Connect,轉到 我的應用 > "+" > "新的Mac應用",並填寫所需的欄位。確定 Bundle ID 與前一階段的配置相符。前綴欄位應為遊戲名稱,例如在我的情況下,它是ufo

你也需要拍攝屏幕截圖,並將它們修剪到正確的大小。只允許以下的尺寸:

  • 1280 x 800 像素
  • 1440 x 900 像素
  • 2560 x 1600 像素
  • 2880 x 1800 像素
6. 應用加載器

下載並安裝最新的應用加載器,用來提交應用。完成以下步驟:

在終端機中填寫內容權限:

    chmod -R a+xr "/path/to/GAMENAME.app"

用第三步中創建的授權信息文件簽署應用:

    codesign -f -s '3rd Party Mac Developer Application: DEVELOPER NAME' --entitlements "GAMENAME.entitlements" "/AppPath/GAMENAME.app"

你可能會遇到以下的錯誤:

    code object is not signed at all

這是因為子元件沒有簽署。你可以逐個簽署它們,包括libmono.0.dyliblibMonoPosixHelper.dylib,但個更簡單的方法是使用深度簽名命令,如下所示:

    codesign -f -s '3rd Party Mac Developer Application: DEVELOPER NAME' --entitlements "GAMENAME.entitlements

" "/AppPath/GAMENAME.app" --deep

然後,構建.pkg文件:

    productbuild --component GAMENAME.app /Applications --sign "3rd Party Mac Developer Installer: DEVELOPER NAME" GAMENAME.pkg

從你的機器中刪除所有已存在的遊戲應用。然後你可以用下面的命令驗證原則:

    sudo installer -store -pkg GAMENAME.pkg -target /

最後,打開應用加載器,選擇'提交你的應用',並選擇GAMENAME.pkg。如果一切正常,上傳應該會成功。否則,根據相應的錯誤來解決問題。這個過程需要一些時間。

7. 選擇構建

如果你收到了包含如下問題的郵件:

> **無效簽名** — 主應用包game在路徑GAMENAME.app有以下簽名錯誤:在架構i386中的Info.plist無效(plist或簽名已被修改)。

這可能是你的某個子元件沒有正確簽署。你可能需要參考蘋果的文件尋找進一步的指導。

否則,返回到iTunes Connect,選擇已上傳的構建,並將狀態從"準備審查"變更為"等待審查" > "審查" > "銷售準備就緒"。

我希望這個博客文章對你有所幫助,也希望可以為你節省一些時間!:)

Resolving Merge Conflicts for the Unity Game Engine

I'm working with a team of four on a Unity 3D game project over the weekends. It's a lot of fun, but we've encountered problems with version control. Using Git and GitHub, we've faced many merge conflicts that are not easy to resolve; it's not as simple as just deleting a section or performing a forced push:

    <<<<<<< HEAD:main.scene
    Painful
    =======
    Delete me
    >>>>>>>

There are lots of unnecessary local meta files that get pushed to our repository. The solution I've found is not perfect, but it works:

First, open the Unity editor and go to:

    Edit -> Project Settings -> Editor ->
    Select "**Visible Meta files**" in the version control mode

Second, add a .gitignore file like this:

    /[Ll]ibrary/
    /[Tt]emp/
    /[Oo]bj/
    /[Bb]uild/
    /[Bb]uilds/
    /Assets/AssetStoreTools*

    # Autogenerated VS/MD solution and project files
    ExportedObj/
    *.csproj
    *.unityproj
    *.sln
    *.suo
    *.tmp
    *.user
    *.userprefs
    *.pidb
    *.booproj
    *.svd

    # Unity3D generated meta files
    *.pidb.meta

    # Unity3D Generated File On Crash Reports
    sysinfo.txt

    # Builds
    *.apk
    *.unitypackage

    .DS_Store

Then, commit the actual changes and run the following commands:

    git rm -r --cached .
    git add .
    git commit -m "Fixed untracked files"

Third, Unity has a tool called UnityYAMLMerge for merging scene and prefab files. Enable this by creating a .gitconfig file with the following:

    [merge]
    tool = unityyamlmerge

    [mergetool "unityyamlmerge"]
    trustExitCode = false
    cmd = /Applications/Unity/Unity.app/Contents/Tools/UnityYAMLMerge merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

The next time a teammate clones the project, they may initially see an empty scene. However, there's no need to panic. Simply open the saved main.scene (assuming you have saved the scene and committed it), and everything else should work as expected. I wish Unity had built-in source control like other IDE environments. Happy coding!

解決Unity遊戲引擎的合併衝突

我正和一個四人的團隊在周末進行一個Unity 3D遊戲項目的工作。這很有趣,但我們遇到了版本控制的問題。使用Git和GitHub,我們遇到了許多不容易解決的合併衝突; 它不僅僅是刪除一個部分或執行強制推送那麼簡單:

    <<<<<<< HEAD:main.scene
    痛苦
    =======
    刪除我
    >>>>>>>

有很多不必要的本地元資料檔案被推送到我們的存儲庫。我找到的解決方案並不完美,但它有效:

首先,打開Unity編輯器並前往:

    編輯 -> 項目設置 -> 編輯器 ->
    在版本控制模式中選擇 "**可見Meta文件**"

其次,添加一個 .gitignore 資料檔案像這樣:

    /[Ll]ibrary/
    /[Tt]emp/
    /[Oo]bj/
    /[Bb]uild/
    /[Bb]uilds/
    /Assets/AssetStoreTools*

    # 自動生成的VS/MD解決方案和項目文件
    ExportedObj/
    *.csproj
    *.unityproj
    *.sln
    *.suo
    *.tmp
    *.user
    *.userprefs
    *.pidb
    *.booproj
    *.svd

    # Unity3D生成的meta文件
    *.pidb.meta

    # Unity3D在崩潰報告上生成的文件
    sysinfo.txt

    # Builds
    *.apk
    *.unitypackage

    .DS_Store

然後,提交實際的更改並運行以下命令:

    git rm -r --cached .
    git add .
    git commit -m "Fixed untracked files"

第三,Unity有一個叫UnityYAMLMerge的工具用於合併場景和prefab文件。通過創建一個.gitconfig文件並使用以下內容來啟用:

    [merge]
    tool = unityyamlmerge

    [mergetool "unityyamlmerge"]
    trustExitCode = false
    cmd = /Applications/Unity/Unity.app/Contents/Tools/UnityYAMLMerge merge -p "$BASE" "$REMOTE" "$LOCAL" "$MERGED"

下次隊伍的某個成員克隆該項目時,他們可能最初會看到一個空的場景。但是,不必慌張。只需打開已保存的main.scene(假設您已經保存並提交了場景),其他東西就應該如預期的那樣工作。我希望Unity像其他IDE環境一樣內置源代碼控制。編碼愉快!