MacBook Pro (Retina, 13-inch, Early 2015) 설치 기록
삽질을 많이해서, 다른 PC에 다시 설치 해본다.
1. 홈브루 설치
https://brew.sh/index_ko
2. cask 패키지 설치 (GUI 기반 app 설치 지원)
$ brew install cask
복수의 자바 버전을 설치하기 위해 사용
$ brew tap homebrew/cask-versions
3. 자바 설치
3.1 자바 버전 확인
$ java -version
3.3. 자주 사용하는 명령어
검색 : brew search [프로그램명]
설치 : brew cask install [프로그램명]
삭제 : brew cask remove [프로그램명]
버전 : brew --version
항목 : brew list
업데이트 : brew update
$ brew install --cask adoptopenjdk8
3.1 자바 버전 확인
$ java -version
openjdk version "1.8.0_242"
OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_242-b08)
OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.242-b08, mixed mode)
3.2. Homebrew에서 설치한 패키지들은 어디에 설치될까?
기본적으로 brew install 명령어를 통해 설치된 패키지는 /usr/local/Cellar 경로에 저장이 된다.
터미널에서 cd 명령으로 위 경로로 이동하고 ls로 목록을 보면 아래와 같이 설치된 패키지들이 보인다.
$ cd /usr/local/Cellar
3.2. Homebrew에서 설치한 패키지들은 어디에 설치될까?
기본적으로 brew install 명령어를 통해 설치된 패키지는 /usr/local/Cellar 경로에 저장이 된다.
터미널에서 cd 명령으로 위 경로로 이동하고 ls로 목록을 보면 아래와 같이 설치된 패키지들이 보인다.
$ cd /usr/local/Cellar
$ ls
3.3. 자주 사용하는 명령어
검색 : brew search [프로그램명]
설치 : brew cask install [프로그램명]
삭제 : brew cask remove [프로그램명]
버전 : brew --version
항목 : brew list
업데이트 : brew update
//========
먼저 젠킨스를 설치 해보자.
$ sudo rm -rf /Library/Developer/CommandLineTools
$ sudo xcode-select --install
2. 젠킨스 설치 lts로 해보자.
$ brew install jenkins-lts
$ brew install jenkins-lts
3. 젠킨스 시작
$ brew services start jenkins-lts
$ brew services stop jenkins-lts
$ brew services restart jenkins-lts
4. 젠킨스 초기 설정
4.1, localhost:8080
4.2, initialAdminPassword 진입
4.3, Install suggested plugins 기본 패키지 설치
4.4, 계정생성
2.289.3 버전이 lts 버전이다. 자바 1.8을 사용하는 버전 업그레이드 하지 말자.
//========
이제 페스트레인을 설치 해보자.
1. 설치
$ brew install fastlane
$ brew install fastlane
2. ruby 버전 확인
ruby 2.6.3p62 (2019-04-16 revision 67580) [universal.x86_64-darwin20]
3. 환경설정 추가
배치 프로파일이 다음과 같지만, zsh로 변경 되면 다르게 사용한다. $ sudo vi ~/.bash_profile
Terminal을 열어 상단 바에 -zsh로 되어 있다면,
$ sudo vi ~/.zshrc
export LC_ALL=en_US.UTF-8
export LANG=en_US.UTF-8
위 내용을 저장하고 적용한다.
$ source ~/.zshrc
4. 해당 프로젝트로 가서, 페스트레인을 적용하자.
$ fastlane init
묻는 질문에 4, 엔터, 엔터, 엔터 하면 완료 된다.
5. FastFile 수정 작업을 한다.
default_platform(:ios)
platform :ios do
lane :dev do
begin
desc "빌드를 시작 합니다."
build_app(
scheme: "swiftuiTest02",
configuration: "Debug",
export_method: "development",
output_directory: "./build/Debug",
output_name: "swiftuiTest02-Debug.ipa",
include_bitcode: false,
clean: true
)
rescue => exception
desc exception
end
end
end
개발자 계정이 아니라서, development로 ipa를 만들었다.
이제 콘솔에서 실행 시켜 본다.
해당 프로젝트 폴더로 이동해서
$ fastlane dev
ipa 생성을 성공하면 다음 단계로 간다.
//========
젠킨스 설정을 변경하여 생성 해보자.
1. 젠킨스 자바 1.8에서 실행 시키도록 변경하자.
$ vi /usr/local/opt/jenkins-lts/homebrew.mxcl.jenkins-lts.plist2. 자바를 교체 합니다.
/Library/Java/JavaVirtualMachines/adoptopenjdk-8.jdk/Contents/Home/bin/java
3. 젠킨스를 재시작 합니다.
$ brew services restart jenkins-lts
4. 이제 추가 패키지를 설치 합니다.
Jenkins관리 -> 플러그인 관리 -> 설치 가능으로 이동
git 인증 관련
Github Authentication
Github Integration
6. 인증 환경설정 추가.
Jenkins 대시보드 -> Jenkins 관리 -> 시스템 설정 -> Global properties 에 들어가줍니다.
추가를 눌러주고
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD
-> https://appleid.apple.com에서 생성된 application specific password 입니다.
-> Ex: xxxx-xxxx-xxxx-xxxx
추가를 눌러주고
FASTLANE_PASSWORD
Github Authentication
Github Integration
루비 실행 관련 패키지
rvm
5. 이제 빌드 아이템을 만들어 보자.
5.1 create item
5.2 freestyle project
5.3 git 주소 넣고,
5.3 git 주소 넣고,
5.3.1 git 설정 -> developer settong -> Personal access tokens
5.3.2 Credentials Add 계정 정보를 넣습니다.
5.3.2 Credentials Add 계정 정보를 넣습니다.
- Domain : Global credentials (unrestricted) 선택
- Kind : Secret text 선택
- Secret : 위에서 생성한 토큰 입력
- ID : 본인이 지정하는 식별자(ID) 입력
- Secret : 위에서 생성한 토큰 입력
- ID : 본인이 지정하는 식별자(ID) 입력
여기까지 하고.
빌드를 해본다. 콘솔창을 보면 소스를 받아온 것을 확인 할 수 있다.
6. 인증 환경설정 추가.
Jenkins 대시보드 -> Jenkins 관리 -> 시스템 설정 -> Global properties 에 들어가줍니다.
추가를 눌러주고
FASTLANE_APPLE_APPLICATION_SPECIFIC_PASSWORD
-> https://appleid.apple.com에서 생성된 application specific password 입니다.
-> Ex: xxxx-xxxx-xxxx-xxxx
추가를 눌러주고
FASTLANE_PASSWORD
-> 개발자 계정 패스워드를 넣어 줍니다 (비번 노출 때문에 배포용 계정을 따로 준비 해야 겠다.)
> 2.6.3 추가
7. 페스트레인 빌드
다시 추가한 프로젝트 아이템으로 와서
> 빌드환경
> Run the build in a RVM-managed environment 체크> 2.6.3 추가
8. 빌드
> Execute shell 추가
> faselane dev
실패.
에러 메세지: fastlane: command not foundrvm, ruby 를 2.7.2로 업그레이드 하자.
1. rvm 설치
$ brew install gnupg
$ gpg --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3 7D2BAF1CF37B13E2069D6956105BD0E739499BDB
$ \curl -sSL https://get.rvm.io | bash -s stable
2. ruby 설치
$ rvm list
$ rvm install 2.7.2
4. 적용
$ rvm use 2.7.2
5. 확인
$ ruby -v
6. 젠킨스를 재시작 합니다.
$ brew services restart jenkins-lts
7. 빌드환경 변경
> Run the build in a RVM-managed environment 체크> 2.7.2
실패.
에러 메세지: fastlane: command not found환경설정에 fastlane 경로 추가.
$ sudo vi ~/.zshrc
export PATH="$HOME/.fastlane/bin:$PATH"
$ source ~/.zshrc
http://localhost:8080/restart 재시작
실패!!
에러 메세지: fastlane: command not found환경설정 추가.
Name: Path
Value: /bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
드디어 fastlane 을 인지했다.
실패!!!
Name: Path
Value: /bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin
드디어 fastlane 을 인지했다.
실패!!!
에러 메세지: fastlane requires your locale to be set to UTF-8
젠킨스 환경설정 또 추가.
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8
성공 . 완료.
//========================================
LC_ALL=en_US.UTF-8
LANG=en_US.UTF-8
성공 . 완료.
//========================================
기타 다른에러.
1. rvenv롤 통해 설치 했을경우 젠킨스 rvm 로드가 안됬다.
수정 rvm 설치
증상 find_spec_for_exe': can't find gem fastlane (>= 0.a) with executable fastlane (Gem::GemNotFoundException)
2. rvenv를 통해 설치 했을 경우 Bundler 버전 문제가 생긴다.
수정 최신 Bundler 설치
수정 최신 Bundler 설치
증상 Warning: the running version of Bundler (2.1.4) is older than the version that created the lockfile (2.2.26).
bundler의 버전 확인
$ gem list | grep bundler bundler (default: 2.1.4)
default버전 삭제
$ cd ~/.rbenv/versions/[루비 버전]/lib/ruby/gems/[루비 버전]/specifications/default
$ ls | grep bundler
$ rm bundler-2.1.4.gemspec
해당 폴더에 파일이 없다면 다른 버전의 루비에서도 찾아보시길 바라요.
bundler 재설치
해당 폴더에 파일이 없다면 다른 버전의 루비에서도 찾아보시길 바라요.
bundler 재설치
$ gem install bundler
//================================
1. 지메일 준비
2.Jenkins 설치시 추천 설치를 했다면 "Email Extension Plugin"이 같이 설치됐을 것입니다.
3. 확장 메일 입력 전에 고급 버튼을 눌러 숨겨진 입력창을 펼쳐주세요.
> SMTP Server: SMTP 서버 주소를 입력합니다. Gmail을 사용하는 경우 "smtp.gmail.com"을 입력
> SMTP Port: SMTP 서버의 포트입니다. SSL을 사용하는 경우는 465
> Use SMTP Authentication: 인증 여부를 선택합니다. 체크해 줍시다.
> User Name: 메일 인증에 사용될 유저입니다. Gmail 로그인 계정을 입력합니다.
> Password: 메일 인증에 사용될 암호입니다. Gmail 로그인 계정의 암호를 입력합니다.
> Use SSL: SSL 사용 여부를 체크해 줍니다. Gmail은 당연히 사용합니다.
> Default Recipients: 메일을 송신할 대상을 정합니다. 공백이면 안되므로 수신 대상의 메일 주소
> Default Triggers: 언제 메일을 송신할지 결정합니다. 일단 테스트용으로 Always를 선택
빌드 후 조치 추가에서 "Editable Email Notification"을 선택합니다.
우선 그대로 두고 "Attach Build Log" 항목만 수정합니다. 이제 메일을 발송할 준비가 모두 끝났습니다.
한번 던져 봅니다.
- name: JENKINS_JAVA_OPTIONS
사용하는 각 job 마다 job 설정에서 remote trigger token을 설정한다.
Job 설정 > 빌드 유발 > 빌드를 원격으로 유발 > Authentication Token
//================================
젠킨스 버전을 올려본다.
2.289.3 -> 2.303.1
성공. 버전은 올려도 된다.
FASTLANE_PASSWORD 제거 테스트, 비밀번호를 넣는게 맘에 안든다.
실패
암호가 있어야 한다.
배포용 애플 계정이 있어야 할듯 하다.
//================================
이제 메일 전송을 테스트 해본다.
보내는 메일 계정을 gmail 로 한다. 이중인증을 해제 한다. 보안수준 낮은 로그인을 허용한다.
2.Jenkins 설치시 추천 설치를 했다면 "Email Extension Plugin"이 같이 설치됐을 것입니다.
그리고, 혹시 몰라서 일단. 패키지를 추가 설치 한다.
Email Extension Template
Email Extension Template
3. 확장 메일 입력 전에 고급 버튼을 눌러 숨겨진 입력창을 펼쳐주세요.
> SMTP Server: SMTP 서버 주소를 입력합니다. Gmail을 사용하는 경우 "smtp.gmail.com"을 입력
> SMTP Port: SMTP 서버의 포트입니다. SSL을 사용하는 경우는 465
> Use SMTP Authentication: 인증 여부를 선택합니다. 체크해 줍시다.
> User Name: 메일 인증에 사용될 유저입니다. Gmail 로그인 계정을 입력합니다.
> Password: 메일 인증에 사용될 암호입니다. Gmail 로그인 계정의 암호를 입력합니다.
> Use SSL: SSL 사용 여부를 체크해 줍니다. Gmail은 당연히 사용합니다.
> Default Recipients: 메일을 송신할 대상을 정합니다. 공백이면 안되므로 수신 대상의 메일 주소
> Default Triggers: 언제 메일을 송신할지 결정합니다. 일단 테스트용으로 Always를 선택
빌드 후 조치 추가에서 "Editable Email Notification"을 선택합니다.
우선 그대로 두고 "Attach Build Log" 항목만 수정합니다. 이제 메일을 발송할 준비가 모두 끝났습니다.
한번 던져 봅니다.
성공, 이제 첨부도 넣고, 메일 내용보 바꿔보고.. 추가 작업 필요.
1. 지메일은 첨부로 ipa, apk 파일은 안된다. - 아웃룩으로 변경.
smtp.gmail.com
465
TLS
SSL/TLS 체크
2. 아웃룩, 전자메일 동기화 설정. - (Admin e-mail address 적어주고 성공.)
smtp.office365.com
587
STARTTLS
SSL 사용 : uncheck / TLS 체크
SSL 사용 : uncheck / TLS 체크
환경설정 추가.
-Djava.awt.headless=true
-Djava.awt.headless=true
-Dmail.smtp.ssl.protocols=TLSv1.2
- name: JENKINS_JAVA_OPTIONS
value: "-Djava.awt.headless=true -Dmail.smtp.starttls.enable=true"
Jenkins Location
Jenkins Location
System Admin e-mail address
위치에 smtp 메일 주소를 적어주면 보내진다.
//================================
<string>--httpListenAddress=0.0.0.0</string>
<string>--httpPort=8080</string>
패키지 설치
Build Authorization Token Root
어휴 성공.
//================================
이제 시리를 이용해 전송 해보자.
https://blog.leocat.kr/notes/2019/06/21/jenkins-remote-triggering-without-authentication
외부에서 진입이 가능하도록 수정한다.
$ vi /usr/local/opt/jenkins-lts/homebrew.mxcl.jenkins-lts.plist
<string>--httpListenAddress=0.0.0.0</string>
<string>--httpPort=8080</string>
내 아이피로 변경한다. 포트는 일반 서비스랑 많이 겹치니 9999 로 바꿔보자
restart 한다.
$ brew services restart jenkins
Build Authorization Token Root
사용하는 각 job 마다 job 설정에서 remote trigger token을 설정한다.
Job 설정 > 빌드 유발 > 빌드를 원격으로 유발 > Authentication Token
호출 URL
기존 REST API 대신 플러그인이 제공하는 별도의 URL로 호출해야 한다. 호출할 때 query string으로 token을 함께 넘겨주고, parameter가 있을 때도 함께 넘겨 주면 된다.
// parameter 없는 경우
{JENKINS_URL}/job/{JOB_NAME}/build?token={TOKEN}
->
{JENKINS_URL}/buildByToken/build?job={JOB_NAME}&token={TOKEN}
// parameter 있는 경우
{JENKINS_URL}/job/{JOB_NAME}/buildWithParameters?token={TOKEN}
->
{JENKINS_URL}/buildByToken/buildWithParameters?job={JOB_NAME}&token={TOKEN}&{KEY1}={VALUE1}&{KEY2}={VALUE2}배포 시나리오가 완성되면,
젠킨스 job의 설정에 들어가서 Build Trigger에서
Trigger builds remotely를 체크하고 토큰 값을 지정해준다.
그러면 이제부터 POST를 날려주기만 하면 배포가 실행된다.
아래의 명령어가 잘 먹는다.
http://192.168.0.9:9999/buildByToken/build?job=test02&token=tokenTest02
http://10.82.32.37:9999/buildByToken/build?job=xxxx_IOS_1_DEV&token=start
http://10.82.32.37:9999/buildByToken/build?job=xxxx_IOS_2_ALPH&token=start
아래의 명령어가 잘 먹는다.
http://192.168.0.9:9999/buildByToken/build?job=test02&token=tokenTest02
http://10.82.32.37:9999/buildByToken/build?job=xxxx_IOS_1_DEV&token=start
http://10.82.32.37:9999/buildByToken/build?job=xxxx_IOS_2_ALPH&token=start
이제 시리 숏컷을 만든다.
단축어 -> + -> 웹 -> URL 콘텐츠 가져오기 -> URL 적기, 메소드 POST
끗
--
아이폰 최종버전.
# This file contains the fastlane.tools configuration
# You can find the documentation at https://docs.fastlane.tools
#
# For a list of all available actions, check out
#
# https://docs.fastlane.tools/actions
#
# For a list of all available plugins, check out
#
# https://docs.fastlane.tools/plugins/available-plugins
default_platform(:ios)
platform :ios do
before_all do
# lane 실행전 수행할 동작을 설정해줄 수 있다
ENV["SLACK_URL"] = "https://hooks.slack.com/services/T017BGR90U9/xxx/xxxx"
# 파이어베이스 토큰, 아이디 - (메일그룹 groups: "hk-tester" 필요)
ENV["FIREBASE_APP_TOKEN"] = "1//0evEiBIveLayrCgYIARAAGA4SNwF-xxxx-xxxx-YbU-xxxxx"
ENV["FIREBASE_APP_ID"] = "1:11861251113:xxxxxxxxxxxx"
end
# 빌드 시작시간
badge_date_time = "#{Time.new.strftime("%m.%d-%H:%M")}"
build_date_time = "#{Time.new.strftime("%m-%d %H:%M")}"
######################### PUBLIC LANES #########################
desc "개발 버전은 드랍박스+슬랙 으로 배포한다."
lane :dev do |options|
ios_get_version_number = get_version_number(target: "타겟명")
# 시작 알림
slack_send(message: "#{build_date_time} 🍏IOS 개발🍏 #{ios_get_version_number}(#{get_build_number}) 빌드시작!", success: true)
# 아이콘에 날짜를 올려준다.
add_badge(shield: "#{badge_date_time}-orange", dark: true)
# 빌드
hk_ios_build(
configuration: "Debug",
export_method: "development",
output_directory: "#{dropbox_directory}",
output_name: "xxxx-Debug.ipa"
)
# 종료 알림
slack_dropbox(message: "#{build_date_time} 🍏IOS 개발🍏 #{ios_get_version_number}(#{get_build_number}) 빌드완료!", success: true)
# 드랍박스 위치에 다운로드 파일 생성
hk_make_download_html(vn: ios_get_version_number, bn: get_build_number)
end
desc "알파버전은 firebase_app_distribution 배포 한다."
lane :alph do |options|
ios_get_version_number = get_version_number(target: "xxxx")
# 버전 코드 증가
increment_build_number
# 깃 푸시
hk_push_to_git_remote(brench_name: options[:brench_name])
# 시작 알림
slack_send(message: "#{build_date_time} 🍎IOS 알파 🍎 #{ios_get_version_number}(#{get_build_number}) 빌드시작!!", success: true)
# 아이콘에 버전을 올려준다.
add_badge(shield: "#{ios_get_version_number}-#{get_build_number}-blue", alpha: true, dark: true)
# 빌드
hk_ios_build(
configuration: "Release",
export_method: "enterprise",
output_directory: "./build",
output_name: "앱이름.ipa"
)
# 테스트 서버 업로드
hk_firebase_app_distribution
# 종료 테스트 링크 제공
slack_button(message: "#{build_date_time} 🍎IOS 알파🍎 #{ios_get_version_number}(#{get_build_number}) 빌드완료!!", success: true)
end
desc "운영 배포한다. 엔터프라이즈 버전이라 담당자에게 메일로 보낸다."
lane :prod do |options|
ios_get_version_number = get_version_number(target: "xxxx")
# 버전 네임 + 코드 증가
increment_version_name(bump_type: options[:bump_type])
# 깃 푸시
hk_push_to_git_remote_release(brench_name: options[:brench_name])
# 슬렉 시작 알림
slack_send(message: "#{build_date_time} 🎂IOS 운영🎂 #{ios_get_version_number}(#{get_build_number}) 빌드시작!!!", success: true)
# 빌드
hk_ios_build(
configuration: "Release",
export_method: "enterprise",
output_directory: "./build",
output_name: "xxxxx_" + ios_get_version_number + ".ipa"
)
# 종료 시작 알림
slack_send(message: "#{build_date_time} 🎂IOS 운영🎂 #{ios_get_version_number}(#{get_build_number}) 빌드완료!!! 잠시 기다리시면 메일이 도착 합니다.", success: true)
end
######################### PRIVATE LANES #########################
private_lane :hk_ios_build do |options|
build_app(
workspace: "xxxx.xcworkspace",
scheme: "xxxxx",
configuration: options[:configuration],
export_method: options[:export_method],
output_directory: options[:output_directory],
output_name: options[:output_name],
clean: true
)
end
# 버전 이름, 코드 증가
private_lane :increment_version_name do |options|
bumpType = options[:bump_type]
if bumpType == nil
bumpType = "patch"
end
# 빌드 넘버를 증가 시킨다.
increment_build_number
#버전 넘버 자동증가
increment_version_number_in_plist(
target: "xxxxx",
bump_type: options[:bump_type] # 자동증가
)
#버전 넘버 자동증가
increment_version_number_in_plist(
target: "ReachService",
bump_type: options[:bump_type] # 자동증가
)
end
desc "웹 후킹을 사용해 슬렉에 메세지를 보낸다."
private_lane :slack_send do |options|
slack(
message: options[:message],
slack_url: ENV['SLACK_URL'],
default_payloads: [:git_branch, :last_git_commit_message]
)
end
desc "친절한 슬렉씨, 다운로드 링크를 제공한다."
private_lane :slack_button do |options|
slack(
message: options[:message],
slack_url: ENV['SLACK_URL'],
attachment_properties: {
actions: [{
type: "button",
text: "IOS 알파 설치하기",
url: "https://appdistribution.firebase.google.com/testerapps"
}]
},
default_payloads: []
)
end
desc "슬렉씨, 드랍박스 링크를 제공한다."
private_lane :slack_dropbox do |options|
slack(
message: options[:message],
slack_url: ENV['SLACK_URL'],
attachment_properties: {
actions: [{
type: "button",
text: "app-xxx-debug.ipa\n16 MB IPA",
url: "#{dropbox_download_link}"
}]
},
default_payloads: []
)
end
# 날짜가 들어간 드랍박스 페이지 생성
private_lane :hk_make_download_html do |options|
Dir.chdir dropbox_directory
out_file = File.open("download.html", "w") { |file| file.write("#{download_html_head} #{build_date_time}<br>xxxx APP #{options[:vn]}(#{options[:bn]})#{download_html_body}") }
end
# lane 수행이 실패하였을 경우 수행할 동작 설정
error do |lane, exception|
slack_send(
message: exception.message,
success: false
)
end
end
# 파이어베이스 배포
def hk_firebase_app_distribution
firebase_app_distribution(
app: ENV['FIREBASE_APP_ID'],
firebase_cli_token: ENV['FIREBASE_APP_TOKEN'],
groups: "hk-tester",
ipa_path: "./build/xxxxx.ipa"
)
end
# 깃 푸시
def hk_push_to_git_remote(brench_name: nil)
remoteBranch = brench_name
if brench_name == nil
remoteBranch = "develop"
end
commit_version_bump
push_to_git_remote(
remote: "origin",
local_branch: "HEAD",
remote_branch: brench_name
)
end
# 깃 푸시
def hk_push_to_git_remote_release(brench_name: nil)
remoteBranch = brench_name
if brench_name == nil
remoteBranch = "develop"
end
commit_version_bump
add_git_tag(tag: "release/" + versionNumber + "_" + buildNumber)
push_to_git_remote(
remote: "origin",
local_branch: "HEAD",
remote_branch: brench_name
)
end
def dropbox_directory
"/Users/xxx/Dropbox/xxxx_IOS_DEV"
end
def dropbox_download_link
"https://dl.dropboxusercontent.com/s/xxx/download.html"
end
def download_html_head
"
<!doctype html>
<html>
<head>
<meta charset='utf-8'/>
<title></title>
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0'/>
<link rel='stylesheet' href=''/>
</head>
<body><h1>
"
end
def download_html_body
"
</h1><BR><BR>
<a href='itms-services://?action=download-manifest&url=https://dl.dropboxusercontent.com/s/xxx/xxxxLauncher.plist'>IOS xxxxLauncher</a>
<BR><BR>
<a href='itms-services://?action=download-manifest&url=https://dl.dropboxusercontent.com/s/xxx/xxxx-Debug.plist'>IOS xxxx_DEV_APP Download</a>
</body>
</html>
"
end
