Lomohome.com :: 괴발자 모근원

iOS12 부터 추가된 단축어앱(구 워크플로우)에서 사용가능한 숏컷입니다.

기본적으론 BMW에서 제공하는 Remote앱에서 [목적지전송]을 통해 차량으로 메세지보내는것과 동일한 기능을 합니다만 Remote앱이 구글지도를사용하여 검색이 안되는 장소가 많아 불편함이 있었습니다.

안드로이드에선 비엠다음맵 (https://play.google.com/store/apps/details?id=org.azki.bmw_x_daummap&hl=ko​) 을 사용하면 되지만 아이폰에선 딱히 방법이 없어 제가 whereugo 라는 앱을 만들었지만, 앱스토어에 올릴 물건이 아니어서 소스를 공개해뒀었습니다. Xcode 컴파일이 가능한 개발자시라면 이쪽도 편리하실겁니다. (https://github.com/moKorean/whereugo​)

그리하여 iOS12 부터 추가된 단축어앱을 이용하여 카카오맵이나 네이버에서 선택/검색한 목적지를 차량으로 보낼수 있는 단축어 extension을 만들었습니다. 사용법은 다음과 같습니다.

-준비물
아이폰, 아이패드와 iOS12 이상 업데이트
단축어앱
(Apple의 단축어 https://itunes.apple.com/kr/app/%EB%8B%A8%EC%B6%95%EC%96%B4/id915249334?mt=8​)


카카오맵( Daum Kakao Corp.의 카카오맵 - 대한민국 No.1 지도앱 https://itunes.apple.com/kr/app/%EC%B9%B4%EC%B9%B4%EC%98%A4%EB%A7%B5-%EB%8C%80%ED%95%9C%EB%AF%BC%EA%B5%AD-no-1-%EC%A7%80%EB%8F%84%EC%95%B1/id304608425?mt=8​) 또는 네이버지도(NAVER Corp.의 네이버 지도, 내비게이션 https://itunes.apple.com/kr/app/%EB%84%A4%EC%9D%B4%EB%B2%84-%EC%A7%80%EB%8F%84-%EB%82%B4%EB%B9%84%EA%B2%8C%EC%9D%B4%EC%85%98/id311867728?mt=8​)

준비물이 다 설치되었으면 사파리에서 아래링크를 복붙하시거나 현재 사파리라면 아래 링크를 누릅니다.


​​BMW목적지 전송 최신버전

​​* v0.1
- 카카오맵에서 차량전송 기본 기능 구현, 첫 배포
* v0.2
- 네이버맵 추가
* v0.3
- 오류케이스 추가
* v0.4
- URL입력 없을시 카카오맵 실행. 위치 가져오는 로직 세분화. 
v0.5
- 로직 수정, 차량여러대 지원 시작
v0.6
- 차량 여러대 지원 수정 thanks to shutterholic

v0.7

- BMW사이트에서 차량 못가져오는 문제 수정

https://www.icloud.com/shortcuts/aa4acc02b947462c981eac5f099101d1



[단축어 가져오기] 를 눌럿을때 앱스토어로 연결된다면 사파리에서 링크를 누른것이 아닙니다. 주소를 복사하여 사파리에서 붙여넣어보세요.

정상적으로 가져와진다면 다음과 같이 BMW connecteddrive 사이트의 아이디와 패스워드를 물어봅니다.
이때 뒤에 공백이나 엔터값이 없도록 잘 입력합니다.


정상적으로 가져왔다면 보관함에서 아이콘이 보입니다.
클릭(탭)하여 선택하시면 기본적으론 카카오맵이 실행되도록 해놨습니다.
카카오맵이나 네이버지도가 실행중이라면 구지 따로 실행할 필요는 없습니다.



사용법은 다음과 같습니다

카카오맵에서 특정 목적지를 검색후 하단의 공유버튼을 누릅니다



다른앱으로 공유하기를 누릅니다



단축어 앱을 선택합니다. 만약 단축어가 안보이면 초록색똥그라미의 더보기를 누릅니다



더보기에서 단축어를 켜줍니다. 이후 숏컷 아이콘들은 길게 눌러 위치를 수정하실수도 있습니다.



단축어가 열리면 BMW 목적지 전송을 누릅니다.



차량의 메세지에 표시될이름을 넣습니다. 그냥 보내셔도 되고 전 차량에서 파악하기 쉽게 ‘근원이네’ 이런식으로도 넣어 사용합니다.



- 끝

은 아니고 몇가지 사용법을 더 알려드립니다.
지도에서 길게누르면 주소가 나옵니다



마찬가지로 주소도 공유를 통하여 차량으로 보낼수 있습니다



- 부록 : 네이버 지도도 마찬가지의 방법으로 차량에 목적지를 전송할수 있습니다.



이후 차량의 메세지에 보면 전송된 지점이 보입니다.
선택해서 신규목적지로 네비게이션 하면됩니다.



- 앞으로 업데이트 되면 현재 블로그 글에 업데이트 하겠습니다.
- BMW ID/PASSWOD 는 본인폰에 저장됩니다. 어디론가 유출되거나 하지않습니다.
- 로그인에 실패하는 경우 ID/PASSWORD 를 넣을때 앞뒤로 공백, 엔터값등이 들어가지 않게 주의하세요.
- 메세지 전송이 안되는경우 BMW차량에서 메세지 수신이 잘 안되는경우가 허다합니다. 한참기다리면 쭈르륵 오거나 하더라구요. 가급적 시동걸기 전즈음 보내고 차량을 탑승해보시면 거진 바로 옵니다.
- 아직 한 ID에 여러대 차량이 등록된경우 선택 기능이 없습니다.  -> 0.6 버전부터 지원


Posted by 모근원
  1. 이전 댓글 더보기
  2. 위에 댓글에 0.8 버전을 쓰셔도 그러하신가요

  3. 므은드레 2019.08.27 18:38

    안녕하세요. 사용법 잘 따라해보니 카카오맵은 안되고( url오류). 네이버 지도는 잘 됩니다.

    0.8 버젼으로 리뉴얼 되었는지 궁금하며
    수정여부와 어디서 받을수 잇는지 궁금합니다.

    현재 0.7 버젼입니다.

  4. 므은드레 2019.08.27 18:42

    위 댓글에 .8 버젼 있네요 ㅎㅎ

    카카오맵도 잘됩니다. 너무감사합니다. 잘쓰겠습니다^^!!!

  5. 안녕하세요
    그동안 개발자님 덕분에 너무 편하게 잘쓰고 있었는데요
    오늘 ios13으로 업데이트된이후로 완전 먹통이 되었습니다 ㅜㅜ

  6. 접근 토큰이 만료되어서 실행이 불가능 한 단축어라 하는데 무엇이 문제일까요?!

  7. 비머붹 2019.09.23 14:50

    모근원 개발자님 ios 13 부탁드려요 ㅠㅠ 안되네요 ㅠ

  8. ios13업데이트 이후에 네이버지도에서는 단축어로 보내는 단추가 보이지 않습니다.
    카카오지도에서는 단축어 메뉴가 보이는데, 동작하지 않고있습니다.

  9. 대물사냥꾼 2019.09.27 23:12

    모근원 개발자님 ios 13부탁드려요~~~~~

  10. 비머붹 2019.09.29 12:02

    최신버전으로 해보니깐 지금은 되네요 분명히 안되었었는데 지금 네이버에서는 단축어로 연결이 안되지만 카카오맵은
    그대로 진행가능합니다!! ios 13.1 입니다 다들 해보시면 가능할거에요 감사합니다!

  11. 칼업스마 2019.10.01 19:30

    저도 접근토큰이 만료되었다고 나오네요.

    잘쓰던건데 안되니 아주 답답하네요.

  12. https://cafe.naver.com/bimmerwerks/448369
    검색하다 찾았습니다. 보내보기만 하고 아직 확인은 못했지만,
    잘 되는거 같습니다.

    모근원님 항상 잘 쓰고 있습니다. 감사합니다.

  13. IOS 13.12 네이버에서 단축어를 찾을수 없고 카카오맵에서는 단축어는 있으나 전송하면 지정된URL 없음으로 나옵니다 꼭좀 되게 해주세요~~ (댓글수정) 댓글읽다가 0.8버젼으로 하니 카카오맵은 잘되네요 네이버에서는 단축어를 찾을수가 없네요 아무튼 감사합니다

  14. iOS 13.2 에서 네이버맵에서 목적지 보내면 지정된 목적지명 대신에 ‘네이버지도‘로 나오며, 좌표 전송이 되지 않습니다. 카카오맵은 문제가 없습니다. 부탁드립니다.

    • 오로로롱 2019.11.05 01:01

      동일 증상입니다. 네이버맵에서 전송된 메시지는 BMW네비 안에서 확인이 가능하지만 그 메시지 안에 주소정보가 없습니다 ㅠㅠ

  15. 강속구 2019.11.04 13:51

    IOS 13.2에서는 공유항목에 단축어가 없는데 어떻게 해야되죠? 네이버지도, 카카오맵 모두요.

  16. 잘쓰다가 갑자기 전송은 되는데 차량에 메세지가 안오네요... 어떻게 해야 할까요??

  17. iOS 13.2 에서 공유항목에 단축어가 없습니다... 해결좀 해주세요 ㅠㅠ 부탁드립니다.

  18. 전송은 완료 되었으나 차에는 메시지가 안옵니다.ios 13.23 입니다.

  19. 황소개구리 2020.01.03 11:52

    단축어 가져오기 눌렀는데 단축어에서 목적지 전송을 열 수 없다고 나오는데 어떻게 해야 하는지요...??

  20. 윤영최 2020.02.10 19:21

    0.8버전 설치하고 차량에 전송하였는데 차량에는 메세지가 들어오지 않습니다. 굉장히 유용한 프로그램인데 지속적으로 팔로우업 해주시면 굉장히 여러 유저들에게 도움이 될 것 같습니다. 노고에 감사드립니다.

  21. 괴발자님화이팅 2020.02.12 15:35

    차량에 메시지가 들어오지 않는데, 괴발자님 피드백 해주시면 정말 감사하겠습니다.
    사랑해요 알라뷰~


안녕하세요 모근원입니다.


2011년. 그러니까 4년전에 iOS5 와 맞추어 새로 등장한 알림센터에 일정을 표시해주던 어플 '일정목록' 을 만들어서 앱스토어에 올렸었습니다.


http://lomohome.com/382



그리고 약 1년후에 애플에 의하여 강제 삭제.. 를 당했었는데요. (알림센터에 위젯이란게 없던시절.. 알림센터에 노티를 이용하여 정보를 남기는것은 사용법 위반)


http://lomohome.com/394


한동안 업무도 바쁘고 이 앱은 쳐다도 보지 못하다가.. 최근에 애플와치를 구입하게 되었습니다.


애플와치에 일정표시하는방법이 맘에 들지않아 iOS9 (Watch os2) 출시 이전에 애플와치용 일정목록 앱을 만들게되면서 


첫 작업으로, 예전 일정목록 앱을 위젯으로 복각 해서 오늘 심사가 통과되었습니다.


3년만의 업데이트라.. 예전앱을 기억하실지 모르겟지만.. 사용법이야 똑같구요.


현재 개발이 거진 완성된 다음버전은 iOS9 (Watch os2)로 나올 예정입니다. 그리고 애플워치 지원과 함께 Tier1 유료 (0.99 아 한국은.. 1.09인가요) 로 판매해볼 계획이니


무료인 지금 다운받으셔서 좋은리뷰 하나씩 남겨주시면 감사하겠습니다 ^^;











앱스토어 링크 : 

https://itunes.apple.com/kr/app/events-widget-events-on-today/id470828213?l=ko&ls=1&mt=8 (한국스토어)

https://itunes.apple.com/us/app/events-widget-events-on-today/id470828213?l=us&ls=1&mt=8 (미국스토어)











** 일부 사용자들에게서 아이폰과 워치가 앱이 연동이 안되는 버그가 있습니다. 애플의 watch os 2 버그로 보입니다 ㅠ 다음을 시도해주세요.


1. 일정위젯을 아이폰에서 삭제하고 아이폰과 애플와치를 모두 껏다 켭니다.

2. 일정위젯을 다시 앱스토어에 받으시고 애플워치에도 설치해주세요. 

3. 먼저 일정위젯을 아이폰에서 실행합니다. 애플워치에선 아직 실행하지마세요.

4. 아이폰에서 캘린더, 연락처 접근권한을 물어보게 되면 허락해주시구요 

5. 그다음 워치앱을 실행시킨다음 2~3분을 기다려주세요.

6. 표시할 일정이 없다고 나오다가 일정이 표시되기 시작하면 아이폰 일정위젯 앱에서 워치부분 설정을 변경하여 입맛에 맞게 설정을 변경합니다.

Posted by 모근원
  1. 이전 댓글 더보기
  2. 님 어디에요 2018.01.22 10:43

    아니 괴발자님 무슨일 생긴거에요?
    앱 스토어에서 저처럼 찾아 해맨 분이 한둘이 아니네요
    무슨일이에요?

  3. 아쉬워요 2018.01.31 10:53

    너무 유용한 앱이었는데 없어서 많이 아쉽네요. 사정이 있겠지만 가능하시면 다시 올려 주시길 부탁드립니다.

  4. 일정위젯좀 2018.02.24 21:23

    업데이트 부탁드립니다.유료로 살께요.애플워치에서 일정보는 유일한앱인데

  5. 악!!! 제발 이어플.. 2018.03.08 14:26

    돌려주세요.. 찾다찾다 여기까지 왔어요 ㅜㅜ... 어디갔나 했떠니 정말 내려간거였네요 .. 이거 진짜 편하구 좋았느넫 ㅜㅜ..

  6. 제발 ㅠㅠㅠㅠ 2018.05.05 19:16

    진짜 거의 반년동안 찾아 헤매엿는데 왜 사라진간가요ㅠㅠ

  7. 저도 이번에 핸드폰 기기변경 중 복원에 문제가 생겨 다시 살릴 수 없던 어플 중 가장 아쉬운 어플입니다. 유로로 올리면 사겠습니다^^

  8. ㅠㅠ 소스는 모두 깃헙에 올리도록 하겠습니다.
    잠수아닌 잠수기간 2년동안 카카오뱅크를 만들고 있었습니다.
    그런데 이제 애플개발자계정도 만료되서 연장도 안하고 있고.. 좀더 본업과 육아에 올인을 하고 있습니다. 짬도 안나네요 ㅠ
    플스4는 사둔지 2년만에 켜고.. ㅠㅠ
    모두 죄송합니다.

  9. 다시 해볼까도 고민해봤지만 '언젠가 업데이트 하겠습니다.' 라고 말해버리면 기다리시는분들이 계실거 같아 부담에 더 작업을 못할거 같습니다 ㅠ
    일이 좀 한가하고 심심하면 취미로 조금씩 하던건데.. 요즘 정말 짬이 안나요 ㅠ

  10. [일정위젯] 재사용 요청 2018.11.05 16:31

    개발자님. 저처럼 "일정위젯" 찾으러 많으분들이 다녀가셨네요.
    저역시 다른 일정위젯을 쓰다가 결국 개발자님 프로그램을 찾게 되어 블로그에 글을 씁니다.
    다시 사용할수 있도록 시간 꼭 내어 주세요. 꼭!!!

  11. 선생님용왕님개발자님... 제가 이 어플때문에 4년만에 핸드폰 바꾼 것을 후회하고 있습니다. 바쁘신 줄 알지만 염치 불고하고 부탁드립니다. 제발 이전 버전이라도 사용할 수 있게 해주세요 다른건 하나같이 다 씅에 안차서 그래요ㅠㅜ

  12. 책임 지세요!!

    다른건 못쓰겠어요..

  13. 수영사랑 2018.12.06 16:52

    저같은 분들이 계시군요~
    개발자님걸 한번 접하고 부터는 다른건 정말 않 맞아요~
    부탁드립니다....
    유료라도 구입하고 싶어요~~~~~

  14. 수영사랑 2018.12.06 16:52

    저같은 분들이 계시군요~
    개발자님걸 한번 접하고 부터는 다른건 정말 않 맞아요~
    부탁드립니다....
    유료라도 구입하고 싶어요~~~~~

  15. 카라얀 2019.01.19 09:59

    같은 분들이 많으시네요.

    앱내린 사유가 어떻게 되는지 모르지만,

    유료로라도 재출시해 주시면 좋겠습니다.

    워치쓰는 이유중 90프로 이상이 일정3개 띄우는거였습니다.ㅜㅜ

  16. 부탁드려요 2019.02.12 01:28

    아이폰 6쓰다 XR로 기변했는데
    일정위젯이 안되네요.
    비슷한거라도 있나 앱스토어 뒤져봐도 없네요.
    부탁드려요^^

  17. 이 어플 찾고찾고 헤매다가 여기까지 왔습니다 ㅠㅠㅠ 제발 ㅠㅠㅠ 유료로라도 쓸게요 ㅠㅠㅠㅠㅠㅠ제발요ㅑ ㅠㅠㅠㅠㅠ

  18. 2년만에 폰바꿨는데 아무리 찾아도 없길래 들어왔는데 이제 못하는건가여? ㅜㅠㅠ제발 다시 내주세요..!!!!ㅠㅠㅠㅠㅔ

  19. 아이폰6에서 정말 잘사용했는데 아이폰8로 기변후에 앱설치가 제대로 안되네요ㅠㅠ
    유료로도 사용할마음이 있습니다 개발자님 바쁘시겠지만 앱 업데이트 부탁드리겠습니다.ㅠ

  20. 개발자님 2019.08.23 08:15

    진짜루 잘 쓰고 있었는데 핸드폰을 바꾸면서 찾아보니 앱이 내려가 있더라고요 ㅠㅠ이만한 일정앱을 찾지 못했습니다 부디 자비를 베풀어주세요 ㅠㅠ

  21. 개발자님 2021.04.29 00:17

    개발자님 .. 이만한 어플이 없어요 정말 .. 찾다찾다.. 여기까지 오게 됐습니다.. 일정 위젯 업데이트.. 불가능할까요.. ㅠㅠ



맥미니를 이용하여 홈서버를 구축하여, CCTV, 웹하드, FTP, 토렌트 다운로드 및 DLNA 등의 서비스를 돌리고 있습니다.

토렌트 다운로드는 많이 알려진 방법대로, Dropbox 의 특정폴더에 torrent 시드파일을 넣으면 uTorrent 에서 땡겨서 다운로드를 받게 만들어두었습니다.

이렇게 하면 외부 어디서든 Dropbox 에 시드파일만 올린다면 집의 서버가 알아서 다운로드를 시작하겠지요.

저는 Request Download 파일이라는 드랍박스 폴더를 만들고, 해당 폴더에 torrent 파일이나 각종 파일들을 다 던져 두면 알아서 파일의 확장자를 가지고 알맞는 폴더로 던져주는 AppleScript 를 이용하고 있습니다.

여기서는 제가 쓰는 AppleScript 의 일부를 보여주고, 대강의 사용법을 알려드리겠습니다.

이 포스팅에서 쓰이는 시나리오는 다음과 같습니다.


1. Request Download 라는 폴더는 torrent 시드파일과, smi, srt 등의 자막파일이 올라올수 있습니다.

2. 토렌트 시드파일은 uTorrent 에서 땡겨가면서 삭제합니다. 토렌트 다운로드가 완료되면 Downloads 라는 폴더에 저장합니다.

3. smi, srt 확장자를 가진 파일은 AppleScript 를 통하여 바로 Downloads 폴더로 옮겨갑니다.

4. Downloads 폴더에 들어간 smi, srt 파일들은 또한 AppleScript 를 통하여 같은 이름을 가진 폴더로 들어갑니다.


먼저 첨부된 스크립트 파일을 확인해주세요.


MoveFileByExt.scpt


moveSubtitleToEachFolder.scpt


내용은 다음과 같습니다. 간략한 설명을 첨부하였습니다.

다운받은 스크립트를 더블클릭하여 경로 등, 자신의 환경에 맞게 수정해주세요.


MoveFileByExt.scpt (이건 Request Download 폴더에 걸 폴더액션 스크립트입니다. 자막파일을 Downloads 로 옮기는거에요.)


moveSubtitleToEachFolder.scpt (이건 Downloads 폴더에 걸 폴더 스크립트입니다. 자막파일을 같은이름의 폴더로 옮기는거에요.)


스크립트 파일을 수정했으면, (다른 확장자를 추가해도 되고, 목적폴더를 여러개 만들어서 if 문을 추가해도 되구요..)

파인더 위의 메뉴바중 [이동] 메뉴에서 [옵션] 키를 누른상태로 라이브러리로 갑니다.

라이브러리 - Scripts - Folder Action Scripts 폴더안에다가 스크립트 파일을 넣어줍니다. (폴더 없으면 만드셔요)



그리고 드랍박스의 Request Download 폴더에서 우클릭, 서비스 - 폴더 적용 스크립트 설정을 클릭합니다.

먼저 이곳에 자막파일이 들어오면 Downloads 폴더로 옮길거에요~


이런 창이 뜨는데 아까 라이브러리 Folder Action Scripts 에 넣어둔 스크립트가 뜰거에요.

MoveFileByExt.scpt 스크립트를 선택합니다.


그럼 위와같이 적용이 됩니다.

그다은, Downloads 폴더에도 스크립트를 걸어줍니다. 이번엔 자막파일을 같은이름의 폴더로 옮기는 스크립트를 걸었어요~




스크립트 설정을 마치고 테스트를 해봤습니다.

Downloads 밑에 AA라는 폴더를 만들고 aa.smi 파일을 Request Download 폴더에 넣어봤더니

Downloads 폴더로 먼저 옮겨간후, Downloads 밑의 AA 까지 잘 옮겨가는것을 확인할수 있습니다.


아래스크린샷은 먼저 Request Download -> Downloads 로 aa.smi 가 옮겨가는 장면,

그리고 AA 폴더를 가만히 보고 있자니..


aa.smi 가 AA 폴더까지 최종적으로 옮겨갔습니다.

아직 저도 AppleScript 를 제대로 공부해본건 아니고, 구글링을 해서 이것저것 짬뽕해서 만들다보니 뭐가 뭔진 잘 모르겠는데요,

조금 공부해보면 파일관리에 굉장히 유용한 방법인것 같습니다. 주기적으로 폴더를 다른곳으로 백업한다던가 하는 스크립트도 짜볼수 있겠구요 (rsync 이용)


Posted by 모근원
  1. 좋은 정보 감사합니다.

  2. 멋집니다. 2018.03.12 14:27

    저도 응용해서 잘 쓰겠습니다.


이번에도 또 애플과의 싸움에서 졌습니다. EventList 에 이어서 UIReferenceLibrary 를 이용한 InDic 또한 앱스토어에서 내려갔습니다.

InDic 에대한 자세한 설명은 이곳으로

이번 어플은 특히 라이센스와의 싸움이었는데요, 소스를 가지고 컴파일하셔서 가지고 다니시거나 수정하여 쓰시는건 문제가 없지만, 앱스토어에 등록하지는 마세요. Enfour, Oxford, Apple 등과 국제 소송에 휘말릴수 있습니다;;


개인적으로는 앱 개발시에 라이센스와 API Document 의 중요성을 인지할수있도록 도와준 앱이었습니다.


먼저, UIReferenceLibrary 의 Document 를 보시면..

https://developer.apple.com/library/ios/documentation/uikit/reference/UIReferenceLibraryViewControllerClassRef/Reference/Reference.html


It should not be used to display wordlists, create a standalone dictionary app, or republish the content in any form.

이라고 써있습니다.


요 API를 이용해서 홀로동작하는 사전어플을 만들면 안되는데, 만들었다 걸려서 내려갔네요.

미리 API문서를 꼼꼼히 확인못한 제 잘못이었습니다.


프로젝트안에는 텍스트파일처리, 인앱, 광고, TTS, 사전API, 등을 쓰는 예제들이 있으니 공부하시거나 현재 진행중인 프로젝트에 참고하실수 있을것 같네요.


많이들 받아가시고 받아가시면 리플 하나씩 부탁드려요~

즐거운 프로그래밍 되셔요~




소스 다운받기 ->

InDic.zip



* 소스보시고 욕하지 마시고;;; 소스엔 매우많은 버그와 허접함이 숨어있을수있습니다.

* 소스의 수정/재배포는 허용하지 않습니다. 

블로그의 링크를 걸어주세요.

Posted by 모근원
  1. 이전 댓글 더보기
  2. asuka0130 2014.01.28 11:18

    고맙습니다. 잘 보겠습니다.

  3. Adnroid개발자 2014.01.29 13:09

    소중한 정보 공유해주셔서 감사합니다.

  4. 비밀댓글입니다

  5. 안녕하세요. 맥부기에서 찾아 들어왔습니다.
    소중한 정보공유 감사합니다.

  6. 조백통 2014.03.15 10:51

    이 어플의 장점은 사파리 상에서 사용하는 '정의' 에도 영향을 주어 사전기능을 슈퍼활성화 시키는게 아닐까 싶습니다. 마치 안드로이드를 쓰는 듯한 기분을 만들어주셔서 감사합니다. 아무래도 이 어플은 펑생 사용하지 않을까 하네요

  7. 소스 공부하는데 유용하게 쓰겠습니다 감사합니다

  8. 풍림화산 2014.05.23 09:41

    고생많이 하셨을텐데 안타깝네요..자료는 잘 쓰도록 하겠습니다.기운내시기 바랍니다. 정말 감사합니다.

  9. 언제부턴가 영어단어를 검색하면 결과가 뜨질 않아요 ㅠ 관리에서 사전을 다운받는 화면에 들어가면 영한 부분 옆이 동그라미 상태로 남아있어요 ㅜ 원래 다운을 받으면 동그라미를 따라 채우면서 다운이 되잖아요? 그냥 얇은파란 동그라미에 멈춰있어요 ㅠㅠ 왜이럴까요...

  10. 고생 많이 하셨습니다. 좋은자료 감사합니다.

  11. 잘 참고 하겠습니다.

  12. 좋은 자료 받아갑니다.
    틈나는대로 분석해보고 제게 피와살이 되도록 잘 사용하겠습니다 ^^~ 감사합니다~!

  13. 진짜 잘쓰고 있어요~
    대학생인데 만들어주셔서 너무 감사합니다!!!

  14. 제가 사용해본 사전 어플중 최고네요
    제일 간편하고 쉽고 유용합니다
    발음선택도 되고 속도조절도 되고 찾아봤던 단어도 저장되고, 정말 제가 찾던 그런 어플입니다.
    정말 감사합니다. 네이버사전 어플이랑 비교가 안되네요, 정말 너무너무 좋아요 ㅠㅠ
    한가지 오타로 잘못검색했을경우에 결과가 없다고 나오는데 유사단어가 밑에 나오다던가 하는 기능이 있었음 더 좋을거같아요, 그럼 이어플은 무료가 아닐지도 모르겠죠?ㅎㅎ 이사전은 정말 심플하고 편하고 유료라고 해도 아깝지않은 어플이네요

  15. 이거 진짜 잘 쓰고 잇아요
    가볍고 !!!

  16. 남미로 2017.07.23 21:42

    안녕하세요. Indic 어플을 너무나도 유용하게 사용했던 유저입니다! 저는 외국에 있을 때와 영어공부를 할 때마다 이 어플을 정말 애용했었는데요. 오늘 제가 5년간 사용한 아이폰 5를 바꾸게 되면서 새로운 폰에 이 어플을 깔려고 앱스토어에서 아무리 검색을 해도 나오질 않아서 개발자님 이름을 앱스토어에서 찾고 이렇게 블로그까지 오게 되었습니다ㅠ 이제 더 이상 이 어플은 앱스토어에서 볼 수 없는 건지요ㅠㅠㅠ?정말 정말 아쉽네요...

  17. 안녕하세요. 잘 쓰고 있었는데 폰을 바꾸면서 다시 내려받기 안되어 이렇게 댓글 답니다.
    혹시 IPA로 받을수 있는지요.

  18. 비밀댓글입니다

  19. 비밀댓글입니다

  20. 비밀댓글입니다

  21. 안녕하세요, 저도 아이폰에서 유용한 사전어플을 찾다보니 방문하게 되었습니다. 이 zip파일압축을 해제하고 사전을 설치해서 사용할 수 있나요? 프로그래밍이나 이쪽으로는 전혀 초보라 여쭤봅니다.

- 애플의 UIReferenceLibrary API의 Standalone 사전 정책에 맞지않아 어플이 내려갔습니다 ㅠ

  그간의 성원에 감사드립니다. 흑



창조경제의 일환으로 앱스토어에 개인개발자 자격으로 올리는 마지막(?)이 될지도 모르는 앱이 등록되었습니다.

운이 좋은건지 나쁜건지 토요일에 앱스토어에 올라오고 바로 사업자등록과 통신판매업을 요구를 하네요... ㅠ

설명 나갑니다.. ㅠ


 


InDic - 간단하고 빠른 사전 어플











iOS7 으로 업데이트되면서 한영 내장사전이 추가 되었습니다.
내장사전을 쓰는 사전어플이 없나 봤더니 QuicDic 이란 앱이 있었습니다. 그런데 영어키보드만 입력이 가능하도록 해놨더라구요..
그래서 한글도 입력이 가능한 간단한 사전앱을 만들어서 지금 앱스토어에 올라가있습니다.


유료버전에는 앞으로 다양한 기능추가를 할 예정입니다.
유료나 무료나 사전 검색하는데에는 차이점이 없습니다.
유료버전에는 광고 라이브러리가 포함되지않아 용량도 더 적고, 빠르고, 가볍습니다.
무료로 전환했습니다.
원하시는 기능이나 제안사항 있으시면 리플이나 메일 주세요~ 최대한 반영하도록 노력하겠습니다.
감사합니다~



- 다운로드 : https://itunes.apple.com/kr/app/indic-gandanhago-ppaleun-sajeon/id723205033?mt=8



* 애플의 API 사용 misuse 로 어플이 내려갔습니다. 그간 성원에 감사드립니다.

Posted by 모근원
  1. 이전 댓글 더보기
  2. 사랑해요 2017.09.21 01:33

    아이폰 업데이트 하는 바람에 내가 제일 아끼던 사전을 못쓰게 됬습니다 ㅠㅠㅠㅠㅠㅠ 너무 쓰고싶습니다..

  3. 이 앱 쓰려고 업데이트 안 하고 있어요 ㅜ

  4. 그동안 앱 잘 썼습니다. ㅠㅜ
    사전 앱 중에 최고였습니다 ㅠ

  5. 다시 받을수없을까요 ㅠ

  6. 슬퍼요.... 2017.10.12 01:55

    너무잘쓰고있었는데 업데이트로 못쓰네요 ㅠㅠㅠㅠㅠㅠㅠㅠㅠ 그동안 정말 감사했습니다...
    다음에 또 좋은 어플로 만나길 기도할게요

  7. 업데이트하고나니까 사용을 못하네요ㅠㅠㅠ 너무 아쉬워요...그래도 그동안 정말 유용하게 잘 사용했어요! 감사합니다!

  8. 비밀댓글입니다

  9. Iamlavender 2017.11.12 14:52

    헝 ㅠㅠㅠㅠ제가 이사전을 정말정말 유용하게 잘썻는데 ㅠㅠ 업뎃하더니 ios11이랑 호환이 안되서 이렇게 찾아보기까지했어요 ㅠㅠ 제가 이용했던 여느 사전들보다 너무 좋아서 안타까워유 ㅠㅠㅠㅠ

  10. 최고의 사전앱 이엿는데 업뎃으로 막혀버렸네요 ㅜㅜ 개발자님 유료어플로 전환해도 좋으니 한번 업뎃해주세요 ㅜㅠ

  11. komme aus 2017.12.07 11:41

    개발자님 덕분에 오프라인에서도 훌륭한 사전을 사용할 수 있었습니다.
    사용하고 있는 아이폰은 iOS11로 업데이트 해버려서 사전사용이 막혀버렸지만 아이패드로는 여전히 잘 사용 중이에요.
    항상 감사드리고 혹시라도 11버전이 호환가능해져서 또 찾아뵐 수 있으면 좋겠네요. 늘 건강하세요. ^^

  12. 너무 좋아하던 앱이였는데 정말 슬퍼요ㅜㅜㅜㅜㅜㅜ업뎃한거 후회중입니다

  13. 저와 같은 사람이 한 둘이 아니군요ㅜㅜㅜㅜㅜㅜ ios11에서 막힌 앱이 너무 많아서 ios10을 장만했는데 앱스토어에도 내려가서 받을 방법이 없네요ㅠㅠㅠㅠㅠ

  14. 이어플 어느 순간 어플 스토어에도 안보이고ㅠㅠ 아니 ios11로 업뎃해서 못쓸 줄 알았으면 업뎃 안했을거에요ㅠㅠㅠㅠ
    아.. 제발 업데이트 해주세요.. 유료버전이라도 제발........ 저 2015년부터 거의 맨날 썼단 말이에요.............ㅇㅏ....

  15. 비밀댓글입니다

  16. 비밀댓글입니다

  17. 쑥갓쑥떡 2018.06.01 17:56

    유료라도 만들어만 주시면 쓸건데.. 업데이트 괜히해서 젤 유용하게 쓰던 앱 못쓰게 되었네요. 개발자님 유료앱 만들어주세요~~~

  18. 늅늅이 2018.08.27 12:21

    개발자님.. 아무리 찾아봐도 이만한 사전 어플은 없는 것 같아요
    다시 APP에 올라올까 기다리다 어제 이 앱이 있던 4S를 초기화 했습니다. ㅜㅜ
    계속 사용하고 싶어요 어떻게 해야 할까요

  19. 늅늅이 2018.08.27 12:34

    그간 이력을 찾아보니 라이센스 문제등 때문에 고생하셨던 것 같네요..
    InDic 은 아쉽지만.. 라이센스 해결된 다른 유료버전 내주시면 써봐야 겠네요
    수고하세요 ~~~

  20. 아이폰유저 2018.09.12 22:37

    아이폰 업데이트했더니 앱이 사라져버렷어요 정말 좋았는데 다시 깔수없네요 이제... 다시 해보실 생각은 없겟죠 아무리 찾아도 더 좋은 사전을 찾을수가 없네요

  21. ㅠㅠㅠ 2018.09.14 04:21

    이 어플 진짜 최고로 요긴하게 쓰던 사전어플이었는데 너무 아쉬워요 정말 ..ㅜㅜ 지금 다른 거 세개정도 받아서 쓰고 있는데 성에 안차네용ㅎ.ㅎ ..
    어플 개발자님 애타게 찾다가 왔는데 포스팅에서 그간 많이 고생하신 흔적이 보이네요ㅜㅜㅜ
    진짜 유료여도 한 번 내주시면 쓸 의향 있는데 한 번 고려해보시는 게 어떨지...? 계획은 따로 없으신가요? ㅠ 진짜 그정도로 너무 좋았어요..!
    진지하게 영어 공부해본 입장으로서 이 사전이 진짜 최고였네용~ 이제는 못쓰게 돼서 너무 아쉽지만 그간 정말 요긴하게 잘 썼습니당 ... 흑흑 정말 감사했어요..!




삼성 SDS 멀티캠퍼스 HTML5 교육중 Sencha Touch 를 이용한 RSS Reader 만들기가 과제로 나왔다.

그런데 과정 커리큘럼상 Sencha Touch 는 겉만 핧고 넘어간다니.. ㅠㅠ

입과 후 수준 테스트에서 괜히 아는척했다가 난이도 상급 과제가 나와서 황당.

어쨋건 Sencha touch 책보고 API 뒤지면서 만들긴 했는데.. 제대로 쓴 문법인진 나도잘 -_-;

책에서는 RSS Feed 를 긁어오기위해 AJAX로 서버통신을 해오는데, 강의실 컴터에 서버를 깔기도 뭐하고 해서

순수 자바스크립트로만 YQL API를 통해 RSS를 리딩하는것으로 변경하였다. thx Stackoverflow!


index.html


rss.js

 

rssfeedlist.js
 

readrssutil.js




SimpleRSSReader.zip





Posted by 모근원

지금은 앱스토어에서 내려간 비운의 앱 일정목록 ㅠ

노티바에 일정을 올려서 편하게 일정을 확인할수 있는 앱!

자세한 설명은 이곳으로


이제는 앱스토어엔 등록되진않지만 혹시 컴파일하여 폰에 깔아두고 쓰실분이나 (저는 이렇게 쓰고있습니다 -_-) 공부하실 목적으로 소스를 보고 싶으신 분들은 (도움이 되려나요;;) 다운받으셔서 맘껏 유린해주세요 -_-; 받아가시면 리플도 하나씩 달아주시구요 ㅠ









소스 다운받기 -> 

EventList.zip


* 소스보시고 욕하지 마시고;;; 소스엔 매우많은 버그와 허접함이 숨어있을수있습니다.

* 소스의 수정/재배포는 허용하지 않습니다. 

블로그의 링크를 걸어주세요.



Posted by 모근원
  1. 대영주모그레인 2013.03.20 08:20

    감사합니다

  2. 이용언 2013.03.20 17:36

    쉽지 않은 결정이셨을텐데 감사합니다.

  3. 좋은 자료 감사합니다.

  4. 봉달이 2013.04.18 12:38

    좋은자료입니다 감사합니다~

  5. 좋은 자료를 공개해주셔서 정말 감사합니다.
    저도 열심히 배우고 만들겠습니다...^^

  6. 봉주르 2013.08.14 12:02

    근원 고마워. 내가누구게~~ ㅋㅋㅋ

  7. 해피헌터 2013.10.02 13:35

    감사합니다^^

  8. 좋은 자료 잘볼게요~

Day:
예쁘고 간편한 디데이 알리미

아이콘 태생부터 우여곡절이 많았던 디데이 앱입니다 ㅠ
오늘 새벽에 앱스토어에 Ready for Sale 되어
블로그에 글 남겨 봅니다 ㅎ


개발자 등록하고 첫 어플인 '일정 목록' 을 만들게 된것은 개인적으로 필요해서 만들어 쓰다가 
너무 꼼수를 많이 부려 정식 앱스토어는 못올라갈것 같았습니다.
그래서 그냥 한번 올려나 봤는데 우연히 얻어 걸려 등록 된것이고..

두번째 앱스토어 등록 앱인 Day: 도 여자친구와 기념일을 카운트 하다가 
다른 D-Day 앱들중 내가 필요한 기능만 뽑아서 간편히 만들어볼 생각으로 만들게 된 앱입니다.

어플 개발 초반부터 아이콘에 대한 고민을 많이 했는데
무조건 심플하고 이쁜 아이콘을 만들고 싶어 초안을 만들어 몇몇 친한 친구들에게 평가를 부탁했지만
 

결과는 참담했습니다. 다들 반응이 너무 촌스럽다 복잡하다 뭐하는건지 모르겠다.. ㅎㅎ

그래서 수정에 수정에 수정을 겪은 뒤에 심플한 최종 아이콘이 나오고 (컨셉은 D - day 입니다 ㅎㅎ)
어플도 친구들의 의견을 최대한 반영해서 약 2주정도 작업을 했습니다.

일본어 버전 번역은 친한친구 박동안님께서 수고해주셨구요 ㅎ


영어는 제가 대충 번역기 돌려 했는데.. 조만간 미국인친구에게 부탁해야겠네요 ㅎ 


그리고 애플에 심사를 올렸는데…

리젝하고 올리고 리젝하고 올리고 리젝당하고 올리고 리젝당하고 올리고 리젝당하고 올리고 ㅠㅠ
어줍잖은 어플 심사해준 사과님께 감사 ㅋ
 
리젝 사유가… 3.4 설치된 어플이름과 iTunes 어플이름이 다르다고…

iTunes에 등록된 어플 이름은 D-Day 였는데
설치되면 Day 만 표시된다고 리젝당하고…

그래서 어플이름을 Day : 로 통일한다음 다시 올렸더니
어플 이름 뒤에 설명이 들어가있어서 키워드로 빼라고 다시 리젝..

그당시 제출한 어플 이름이
Day : Simple and Beautiful D-Day reminder - 예쁘고 간편한 디데이 알리미
였는데 뒤에 한글 설명이 문제가 되었습니다.

한글 사용자들 검색때문에 넣어둔것이었는데 
이전 앱은 잘 통과되더니.. 리뷰어 제대로 된통 걸렸다 싶었습니다.

그래서 그부분을 다시 키워드로 빼놓고
다시 올리니 이틀만에 승인이 났네요 ㅎ 

일단 어플 자체는 굉장히 심플하지만 개발하면서 새로운 부분 공부한것도 많고
새로운 기술을 적용한 부분도 많아서 알아주신다면 감사하겠습니다 ^^; 
기술적인 부분보다도 예쁜 어플 화면에 집중한것도 있구요.. 폰트라던지.. 
아직 버그도 많고 추가해야겠다고 예정만 하고 아직 들어있지 않은 기능도 많지만
많이 다운받아 주시고 격려의 한말씀 부탁드릴게요 ㅎㅎ

Posted by 모근원
  1. 이전 댓글 더보기
  2. 비밀댓글입니다

  3. 비밀댓글입니다

  4. 비밀댓글입니다

  5. 비밀댓글입니다

  6. 비밀댓글입니다

  7. 저 비밀번호를 잊어서요ㅠㅠ 어떻게 못찾을까요!!!????

  8. 저 비밀번호를 잊어서요ㅠㅠ 어떻게 못찾을까요!!!????

  9. 저 비밀번호를 잊어서요ㅠㅠ 어떻게 못찾을까요!!!????

  10. 비밀댓글입니다

  11. ios 11로 업데이트 되면서 앱이 열리지가 않네요.....안에 날짜 정보를 볼수 있는 방법이 없을까요?

  12. ios11과 호환 될 수 있 게 업 데 이 트 좀 해 주 세 요

  13. 업데이트 2017.10.18 00:14

    안녕하세요. 앱 개발자님 Day라는 앱은 제가 아이폰을 처음 쓸때인 2013년도부터 써왔습니다. 유일하게 유료로 구입한 디데이 앱이기도 합니다. 업데이트 바랍니다. 계속 사용하고 싶습니다 .... 안에는 소중한 디데이들이 많이 있습니다 ... 잊지말아야할 디데이나 좋은 정보들도 메모처럼 사용해왔습니다. 업데이트 부탁드립니다 ㅠㅠ

  14. 업데이트 2017.10.23 13:26

    Ios11과 호환 될 수 있게 업데이트좀해주세요 ㅠ
    어플에 설정되어있는 정도 확인하는 방법은 없나요??ㅠ

  15. 사용하게 해주세여 2017.10.24 16:49

    업데이트이후 사용이 안되는데 업글하실 의향이 없으신건가여? 안에 내용이라도 확인하고 싶은데
    부탁드립니다

  16. 사용방법좀요 2017.10.27 19:47

    업데이트를 안 하실거면 안에 내용을 볼수 있는 방법만 이라도 알려주세요.

  17. 답답 합니다. 2017.11.10 11:35

    업데이트를 안 하실거면 안에 내용을 볼수 있는 방법만 이라도 알려주세요!

  18. 개발자님 이거 제발ㅜㅠ 11버전에서 살려주세요 아니면 기록 조회라도 해서 백업해서 파일로 보내는 방법이라도...... 여기에 소중한 기념일이 다 있는데 11버전에선 호환이 안돼요ㅠㅠ

  19. 많은분들이 댓글 남겨주셨는데 안에 내용 확인할수 있는 방법은 없는건가요? 진짜 답답합니다... 가능하다 불가능하다 얘기라도 좀 해주세요ㅠㅠ 앱 안에 추억할만한 디데이가 많이 들어있는데...

  20. 안의 내용은 sqlite 로 되어있습니다. 별도 암호화는 없어서 그냥 읽으시면 되는데 방법이 어렵습니다.
    애플계발자 계정은 만료가 되어 새로이 앱스토어에 올릴수는 없습니다.
    그동안 사용해주셔서 감사합니다 ㅠ

  21. 제발 안에 내용 볼수있게 해주세요
    중요한 기념일들을 볼수가 없어서 속상합니다 제발

현재 iTunes App Store 에서 삭제 당했습니다.
그간 성원에 감사드리오며 더 좋은 앱으로 보답드리겠습니다 ㅠ


iOS5 부터 추가된 노티센터에 앞으로의 일정을 쭉 표시해주는 앱을 만들어서 몇달간 앱스토어에 올렸었는데요.

 

이번에 애플직원이 심심했는지 레디포세일중에 제 앱을 가지고 딴지를 걸었네요..

 

처음엔 노티센터에 일정을 등록하는데 non-public APIs 를 쓴것이 아니냐 그래서...

 

I would like to talk to you about your app submission. Specifically, the use of the Notification Center.
 

 
장문의 이메일을 보냈는데.. non-public API는 한개도 쓴것이 없고 노티센터에 local-push notification 을 이용하여
 
메세지 등록을 시키고 있다 라고 했더니..
 
오늘 답변이 온것이..
 
This is not an intended use of the Notification Center and the following needs to be removed for the app to remain for sale.
 
 
1) The app places the events from iCal into the notification center to be displayed until the event happens. This is a notification center misuse (2.5)
2) App contains a shortcut to the Settings app in the Information section (2.5)... change was not verified in ver. 3.11
3) When the scheduling is complete, the app presents a Quit button (10.1)
 
1.노티센터에 앞으로의 일정을 표시 시키는것이 노티센터를 지들이 정한 용도에 맞지않게 쓰는것이며 (misuse),
2.iOS 5.1에서 제거된 셋팅숏컷이 남아있고 (이건 없앴는데! 이상하게도 ㅠ)
3.노티센터에 일정등록이 완료되면 종료버튼 (exit(0)) 이 있어서 가이드라인 위반이라고 하네여...
exit(0)은 종료 메세지 띄운뒤에 나오면 되는줄알았더니만..
 
2번 3번은 어찌 수정하면 될것 같지만.. 노티센터에 일정을 보이게 하는게 가이드라인 위반이라면
이 앱의 존재자체가 필요없기 때문에..
한번더 메일을 보내봐야 알겠지만 곧 앱스토어에서 내려가게 될것 같습니다.
 
혹시 이런 자질구레한 앱이지만 필요하신분들은 내려가기전에 어서 받으셔서 사용하시면 될것 같습니다.
허접스런 앱이지만 오늘 기준으로 5만여분이 받아주셔서 쓰시고 유용하다는 리뷰도 많이 받았었는데 ㅠㅠ
 
안타깝네요 ㅠ 흑
 
*내려가기전에 iTunes 에서 IPA 파일을 백업받아두시면 계속 쓰실수 있습니다 ㅠ 흑





일정목록 (Events List)

 비밀리에 -_- 개발이 진행되었던 일정관리 어플이 드디어
앱스토어에 출시 되었습니다.

아래는 클리앙에 올린 소개글 전문.
개발비화도 살짝... -_- 

 

일단 제가 만들었고. 버그도 많고 거지같습니다만;;;

 

개발자 등록하고 난생 처음 리뷰를 통과한 어플이라 (엉엉 ㅠㅠ) 한번 소개글 올려봅니다.

 

iOS5 에 알림센터가 생겼는데요

 

알림센터를 주욱 내려서 향후 일정을 표시하면 어떨까.. 싶어서 iOS5 beta 1 때부터 조금씩 만들었었는데요

 

beta 4인가 5부터... 알림센터에 [캘린더] 로 일정이 나오더라구요 -_-;;;;;;;;;;;;;;;; 원래 없었는데!!!

 

그래도 강점이라면 [캘린더] 위젯은 오늘, 내일 일정만 나오는데 제 어플은 기간 관계없이 향후 일정을 표시합니다!

 

근데 단점이 더 많아요.... 알림센터 위젯을 어플에서 접근가능한 API 가 없어서... (그렇게 알림센터좀 같이 쓰자고 애플에 숱한 메일을 보내봤지만 ㅠㅠ)

 

일정이 추가 삭제 될때마다 다시 어플을 실행시켜서 업데이트 시켜주셔야 합니다-_-;;;;

 

완전 꼼수 어플이에요. 로컬 노티를 막 보내서 알림센터에 줄창 떠있게 하는.... 리젝당할줄 알았는데 통과되데요;;;

 

아... 이렇게 쓰니까 춫천app 카테고리보다 잡담에 들어가야할것 같네요 ㅠ

 

더 유용한 어플을 만들수 있게 저에게 힘을 주세요~~ :-)

 

아... 어플 링크를 빼먹었네요.

 

꽁짜니까 부담없이 받으셨다가 지워주세요 ㅎㅎ

 

- 미국 스토아

http://itunes.apple.com/us/app/events-list/id470828213?l=ko&ls=1&mt=8

 

- 한국 스토아

http://itunes.apple.com/kr/app/events-list/id470828213?l=ko&ls=1&mt=8

 

* former 를 future 로 바꾼 버전 2 도 지금 심사중입니다! 확인하실겸 버젼 2 도 받아주세요. (나중에~) 


Posted by 모근원
  1. 샬랄라 2011.10.14 16:20

    오오오~럴쑤럴수이럴수~안그래도 스케줄러같은거 어플 계속찾고 있었는데~
    근원님 짱입니다~!!ㅎㅎ
    궁금한데;; 소니 넥스는 사용하기 괜찮은가요?
    요즘 DSLR은 처박아둬서ㅠ_ㅠ 펜과 소니중에 고민중임다~ㅎㅎ
    얼른가서 어플받아보겠음~두둥

    • 오오오. 오랬만이에요~ ㅎㅎ
      이건 스케쥴러같은 거창한건 아니구요 그냥 표시 앱이에요 ㅠ

      넥스 오래쓰다 보니 좋은데 작은 카메라중엔 사진 색감은 DP2 가 제일 좋았던것 같아요 ㅠ

  2. 작은꿈 2011.11.10 16:56

    딱 원하는 기능이네요.
    그런데 리스트에 일정 각 항목마다 일정목록이라고 뜨네요.
    일정목록 보다는 아래나오는 제목이 위로 올라왔으면 좋을듯 합니다.

    • 안타깝지만 노티바를 커스터마이징 할수 없기때문에
      각 항목마다 일정목록 이라고 뜨는것과 오른쪽에 추가된 시간 뜨는것은 개발자가 변경할수 없습니다 ㅠㅠ
      애플을 탓해야겠지요.
      나중에 방법이 생기면 첫번째로 적용하겠습니다
      관심가져주셔서 감사합니다 ㅠ

  3. 어플잘받아서쓰구잇는 처자입니다(감사염^^)
    목록 3개 혹은 자기가 목록 갯수 지정하는건 어찌 안댈까요??

    • 항상 목록을 표시한다는게.. 애플의 알림센터 표시 갯수를 이용한 꼼수이기 때문에. 설정에서 정한 1,5,10 (아이패드는 20개까지) 의 단위로 밖에 지정이 안됩니다.

      좋은 방법이 생각나면 업데이트때 반영하겠습니다. 감사합니다 :-)

  4. 좋은어플이에요^^ 잘쓸께요~ 추후 업데이트 잘 부탁드립니다.

  5. 좋은 앱 잘쓰고 있습니다.. 광고도 틈나는대로 누르고 있구요 ^^
    근데 저도 앱개발하는 입장에서 궁금한것이 이앱은 특이하게 일정등록시에 alertbox가 뜨지 않고 바로 noticonter에 등록이 되더군요... 설정에서 알림스타일을 해놓아도
    [[UIApplication sharedApplication] presentLocalNotificationNow:local];
    이딴식으로 현재 noti를 하면 바로 등록하도록 하면 배너나 알림박스가 나오고 등록이 되던데... 몇가지로 테스트해봐도 되질않아서 여기에 질문글 남깁니다.. 그럼 좋은하루되시길

    • 따로 어플에서 설정하는건 없구요.
      알림센터에서 알림 스타일을 '없음'으로 해두면 알림박스가 안나옵니다.
      다시 테스트 해보세요~

  6. 나그네 2011.11.24 10:01

    앱내 제거 말고 유료버젼 만들어 주시면 안될까요 4 쓰는데 4s로 바꾸면 또 결제 해야해서요...

    • 어플 다시 받으신다음 같은 iTunes 계정으로 결재 하시면 이미 결재한 내역이라 꽁짜로 적용한다는 메세지가 나오십니다. 고갱님~

  7. 일정목록 어플을 설치서 즉시업데이트를 했는데, 기본 어플 캘린더에 있던 지난일정들이 모두 삭제되었습니다. 삭제된 지난일정을 복원할수 있는 방법있으면 알려주세요? 애플에서는 동기화 않해서 불가입니다. 어플 개발자께서 알고 있을거라 판단됩니다.. 답변기다리겠습니다..

    • 일정은 EKEventStore 에서
      - (NSPredicate *)predicateForEventsWithStartDate:(NSDate *)startDate endDate:(NSDate *)endDate calendars:(NSArray *)calendars;
      메소드를 통하여 가져옵니다.
      프로그램안에는 일정을 수정,삭제하는 어떠한 명령어도 없습니다.

      일정목록 어플은 기기내의 일정을 읽어오기만 하지 기기의 일정을 수정, 삭제 하지 않습니다.
      혹시 다른 칼렌다 어플에서 삭제,동기화 되지 않았는지 확인해보셔야 할것 같습니다.
      일정을 다른 서버들과 동기화 하지 않는다면 복원할수 있는 방법도 없을것 같네요.
      일정은 구글캘린더 등 다른 서버와 동기화 하시는것이 백업과 관리에 용이할 수 있습니다.
      도움이 되셨으면 좋겠네요.

  8. 제가 원하던 어플이어서 예전에 받았지만... 한국분인줄 몰랏네요
    먼저 아이튠즈로 저번에 일정목록 글자 하나하나 다 뜨는거 글 남겻는데
    올라왓는지 모르겟네요... 이거 수정해주셧으면 합니다...

    그리고.. 자동 업데이트는 위에 글 읽어 보니... 애플정책상안되는거 같고.....

    좋은 어플 감사합니다... 미리 메리 크리스마스입니다.

    • ㅠㅠ 그게... 노티바를 커스터마이징 할수있는 방법이 아직은 없습니다.
      가만히 보시면 다른 어플들도 죄다 타이틀이 뜰거여요.
      다음에 그곳을 없앨수 있는 API가 공개된다면 제일먼저 반영하도록 하겠습니다.
      관심가져주셔서 감사합니다 (_ _)

  9. 윤희중 2012.01.18 23:21

    안녕하세요 어플잘 사용하고 있습니다 옙내 구매로 공고를 제거해서 쓰고 있습니다. 일정목록을 최근 5개로 사용하고 있는데 알림에는 계속 하나만 뜨네요. 설정-알림으로 들어가서 최근 5개로 설정해서 쓰고 있는데도 알림에서는 계속 1개의 일정만 뜨고 있습니다. 4s 5.0.1을 쓰고 있습니다 순정이구요

  10. 복원하고 다시 받을려 했더니 아이튠즈에서 사라졌네요.ㅋ
    완전히 내린건가요?

    • 애플의 딴지로 삭제 '당'했습니다. ㅠㅠ
      그전에 백업이나 동기화로 IPA 파일이 있으시다면 설치가 가능하시겠지만. 없으시다면 불가능하십니다.

  11. 제발... 2012.11.22 00:36

    아이폰3GS에서 잘받아 쓰다가 4로 넘어왔는데 이거 멘붕이에여 IPA파일 보내주시고 사용할수있게좀 만들어주세요 제발...ㅜㅜㅜㅜㅜㅜ 자세한 상담은 메일로좀 해주세염 ppp777555@naver.com 기다릴게요 개발자님ㅠㅠ

  12. ㅇ찾다찾다 찾은 어플인데.... 결국은 삭제된거였군요.....아ㅏㅏ너무!!!아쉬워요~ㅠㅠ

  13. 한스버그 2013.02.16 13:59

    Ipa파일좀 보내주세요ㅠ
    Extremedog77@naver.com

- 개인적인 용도로 요약한 글이라 글에서는 경어체를 사용하지 않습니다. 양해부탁드립니다.

- 회사에서 진행하고 있는 프로젝트와 관련이 있어 과도한 모자이크가 있습니다. 양해부탁드립니다.
- Mac 의 Pages로 작업했으나 블로그에 올릴때 레이아웃이 많이 깨졌으므로 PDF로 다운받아보시는것을 권장합니다.

 

iOS 4.1 부터 지원하기 시작한 Apple의 GameCenter 를 내 어플에 붙여보는 작업을 해보자.

GameCenter 의 가이드가 잘 되어있으니 전체적인 개발방법은 가이드를 참고해보고 이번 포스팅에서는 속성으로 필요한 부분만 정리해서 올려본다.


간단히 GameCenter는 지원하는 어플의 세계 랭킹, 도전 목표, 같이 게임을 하는 친구목록 등을 지원하고 또한  Auto-Match (대전상대 매치), 음성채팅같은 API도 제공된다. (이전에 Apple이 지원하기전에는 OpenFeint 등이 유명한 솔루션이었다)



-참고 : Apple의 GameCenter Developer guide

http://developer.apple.com/library/ios/#documentation/NetworkingInternet/Conceptual/GameKit_Guide/GameCenterOverview/GameCenterOverview.html


1. 사전작업 

먼저 어플이 iTunes connect 에 등록이 되어있어야한다. (https://itunesconnect.apple.com)

개발자 계정을 입력후 로그인하면 Manage Your Applications 라는 메뉴를 누른다.


그 다음화면에서 GameCenter를 적용할 어플을 클릭한다.


그다음 Manage Game Center 를 눌러서 게임센터 관리로 들어간다.


여기서 Game Center 를 Enable 시켜준다. 

이미 테스트용도로 Enable 시켰기때문에 화면에서는 Disable 로 표시된다.

 

Leaderboard 는 간단히 말해 점수판이다. 전세계 사용자들과 나 자신의 점수를 비교해볼수도 있고 GameCenter에 친구들이 같은 어플(게임)을 사용한다면 친구들간의 순위도 제공된다.


먼저 점수판을 하나 셋팅해본다. Edit 를 누른뒤 Add Leaderboard 버튼으로 점수판을 하나 생성한다.

테스트 용도이므로 Single Leaderboard 로 생성을 했다.

Leaderboard Reference Name 은 내가 알아볼만한 이름으로 셋팅하면 되고

Leaderboard ID 가 중요한데 프로그램에서 참조되는 값이므로 유니크한 이름으로 셋팅해야된다.

Sort Order 는 오름차순,내림차순 정렬등을 선택하고 Add Language 버튼으로 언어별 표시되는 이름 뒤에 붙는 점수표시법등을 설정할수 있다.

 

그다음 다시 Manage 화면으로 와서 이번엔 게임 목표(Achievements)를 설정해본다.

목표는 어플당 1000점 한도 내에서 목표1개당 1~100점 이내로 여러개를 설정할수 있다.

Add New Achievement 버튼으로 새로운 목표를 하나 만들어 본다.



Achievement Reference Name 은 iTunes Connect 에서 관리하게 편하게 알아볼만한 이름으로 설정한다.

Achievement ID 는 마찬가지로 프로그램에서 참조할 이름을 적어준다.

Hidden 은 공개된 목표인지, 숨겨진 목표인지 설정하고 

Point Value 로 목표를 완수했을때 주어지는 점수를 셋팅한다. 100점까지 셋팅이 가능하다.

Add Language 버튼으로 언어별로 표시될 이름, 목표 완수전에 표시될 설명, 완수 후에 표시될 설명, 그리고 목표에 해당하는 아이콘이미지를 넣어준다.


테스트로 몇개 만들어보고 이상으로 iTunes Connect 사이트에서 설정할 사전작업은 완료되었다.




2. 코드적용
 

2.1. 라이브러리 추가

xcode 를 열고 즐거운 코딩작업을 시작한다.

먼저 GameKit 라이브러리가 프로젝트에 포함이 되어야한다.

xcode 4 로 넘어오면서 이게 어디있나 한참 찾았는데 xcode 4에서는 다음에서 필요한 라이브러리를 포함시킬수 있다.

프로젝트파일을 선택하고 Targets 에서 선택하고 Build Phases 를 누른후 Link Binary with Libraries 에서 

GameKit.framework 를 추가해준다.




그리고 게임센터에서 점수를 기록하거나 목표를 달성했을때 게임센터 스타일의 노티를 붙여주기 위해 typeoneerror블로그의 GKAchievementNotification 소스를 추가로 붙이기 위해서 ,다운받은 (링크는 아래에... 그리고 블로그에도 첨부파일로) 소스와 이미지들을 프로젝트에 추가해준다.

(여기에선 typeoneerror-GKAchievementNotification-8a90404.zip 사용)


 

http://www.typeoneerror.com/articles/post/game-center-achievement-notification


겜센터 스타일의 노티가 기본적으로 뜰때 풀사이즈의 어플을 기준으로 했기때문에 내가 작업하고 있는 어플에서 보면 노티가 나오다가 짤려보인다.

문제는 20픽셀을 잡고있는 스테이더스바 때문인데 스테이더스바의 길이만큼 더해서 노티가 더 내려오도록 수정을 했다.

다음 수정은 상단에 스테이더스 바가 있는 어플일때만 해주면 된다. (자신의 어플에 맞게 Customize 해서 쓰도록하자)


다운받은 소스의 GKAchievementNotification.h 의 파일을 보면 다음과 같은 정의구문이 있는데 기본 10픽셀만큼 내려오는걸 30필셀만큼 내려오도록 수정한다.


#define kGKAchievementFrameEnd      CGRectMake(18.0f, 10.0f, 284.0f, 52.0f);

여기서 10.0f 를


#define kGKAchievementFrameEnd      CGRectMake(18.0f, 30.0f, 284.0f, 52.0f);

이렇게 30.0f 로. (20픽셀만큼 더함)




2.2. 게임센터 접속 메소드 구현


게임센터를 접속시켜야하는데 MainView 쪽에 작업해도 되지만 나는 어플안에서 마구 가져다 쓸수 있는 인스턴스 클래스에 접속,점수 보내는등의 메소드를 구현해놨다.


인스턴스 클래스 AppUtils.h

#import <GameKit/GameKit.h>

#import "GKAchievementHandler.h" //이건 노티를 위해서 임포트


@interface AppUtils : NSObject {

~~~~

}

~~~~

/////////////////Geunwon,Mo : GameCenter 추가 start /////////////

+ (BOOL) isGameCenterAvailable ; //게임센터가 사용가능하지 알아보는 메소드

+ (void) connectGameCenter; //게임센터에 접속하는 메소드

+(void) sendScoreToGameCenter:(int)_score; //게임센터서버에 점수 보내는 메소드

+ (void) sendAchievementWithIdentifier: (NSString*) identifier percentComplete: (float) percent;//게임센터서버에 목표달성 보내는 메소드

+ (void) resetAchievements; //테스트용으로 목표달성도를 리셋하는 메소드

/////////////////Geunwon,Mo : GameCenter 추가 end   /////////////


@end

 


AppUtils.m

~~~(생략)


/////////////////Geunwon,Mo : GameCenter 추가 start /////////////


//GameCenter 사용 가능 단말인지 확인

+ (BOOL) isGameCenterAvailable { 

    // check for presence of GKLocalPlayer API

    Class gcClass = (NSClassFromString(@"GKLocalPlayer"));

    // check if the device is running iOS 4.1 or later

    NSString *reqSysVer = @"4.1";

    NSString *currSysVer = [[UIDevice currentDevicesystemVersion];

    BOOL osVersionSupported = ([currSysVer compare:reqSysVer options:NSNumericSearch] !=NSOrderedAscending);

    return (gcClass && osVersionSupported);

}


//GameCenter 로그인

+ (void) connectGameCenter{

    NSLog(@"connect... to gamecenter");

    if([GKLocalPlayer localPlayer].authenticated == NO) { //게임센터 로그인이 아직일때

        [[GKLocalPlayer localPlayerauthenticateWithCompletionHandler:^(NSError* error){

             if(error == NULL){

                 NSLog(@"게임센터 로그인 성공~");

             else {

                 NSLog(@"게임센터 로그인 에러별다른 처리는 하지 않는다.");

             }

        }];

    }

}

// 게임센터 서버로 점수를 보낸다.

+(void) sendScoreToGameCenter:(int)_score{

    GKScore* score = [[[GKScore allocinitWithCategory:@"kPoint"]autorelease];

    // 위에서 kPoint 가 게임센터에서 설정한 Leaderboard ID

    score.value = _score;


    // 아래는 겜센터 스타일의 노티를 보여준다. 첫번째가 타이틀, 두번째가 표시할 메세지

    [[GKAchievementHandler defaultHandlernotifyAchievementTitle:@"NBank Point!"andMessage:[NSString stringWithFormat:@"NBank Point %d점을 기록하셨습니다.",_score]];

    

    // 실지로 게임센터 서버에 점수를 보낸다.

    [score reportScoreWithCompletionHandler:^(NSError* error){

        if(error != NULL){

            // Retain the score object and try again later (not shown).

            

        }

    }];

}


// 게임센터 서버로 목표달성도를 보낸다. 첫번째가 목표ID, 두번째가 달성도. 100%면 목표달성임

+ (void) sendAchievementWithIdentifier: (NSString*) identifier percentComplete: (float) percent{

    NSLog(@"--겜센터 : sendAchievementWithIdentifier %@ , %f",identifier,percent);

    GKAchievement *achievement = [[[GKAchievement allocinitWithIdentifier: identifier]autorelease];

    if (achievement)

    {

        achievement.percentComplete = percent;

        

        [achievement reportAchievementWithCompletionHandler:^(NSError *error)

         {

             if (error != nil)

             {

            

             }

         }];

        

        // 이 아래는 게임센터로부터 목표달성이 등록되면 실행되는 리스너(?)

        [GKAchievementDescription loadAchievementDescriptionsWithCompletionHandler:

         ^(NSArray *descriptions, NSError *error) {

             if (error != nil){}

                 // process the errors

             if (descriptions != nil){

                 

                 //목표달성이 등록되면 노티로 알려준다.

                 for (GKAchievementDescription *achievementDescription in descriptions){

                     if ([[achievementDescription identifierisEqualToString:identifier]){

                         // 보낸 ID와 일치하면 달성도에 따라 노티를 보여준다.

                         if (percent >= 100.0f) { // 100%면 달성완료 노티를...

                          [[GKAchievementHandler defaultHandler]notifyAchievement:achievementDescription];   

                         else { // 100%가 안되면 진행도를 노티.

                             [[GKAchievementHandler defaultHandler]notifyAchievementTitle:achievementDescription.title andMessage:[NSStringstringWithFormat:@"%.0f%% 완료하셨습니다.",percent]];

                         }

                     }

                 }                           

             }                     

        }];    

    }



// 테스트할때 현재까지 모든 진행도를 리셋하는 메소드.

+ (void) resetAchievements

{

    // Clear all progress saved on Game Center

    [GKAchievement resetAchievementsWithCompletionHandler:^(NSError *error)

     {

         if (error != nil){}

             // handle errors

    }];

}


/////////////////Geunwon,Mo : GameCenter 추가 end   ///////////// 



이제 어플을 실행하고 메인 뷰 컨트롤러의 viewDidLoad 메소드에 게임센터 접속을 코딩한다.

이 프로그램에서는 MainMenuViewController.m 에다가 코딩해놨다.

#import "AppUtils.h"


~~~~~(생략)

- (void)viewDidLoad {

~~~~~(생략)

    /////////////////Geunwon,Mo : GameCenter 추가 start /////////////

    

    //AppUtils 가 인스턴스 메소드이기 때문에 걍 쓴다

    if ([AppUtils isGameCenterAvailable]) { //게임센터가 가능한 단말이면...

        [AppUtils connectGameCenter];       //게임센터 접속~

    }

    /////////////////Geunwon,Mo : GameCenter 추가 end   /////////////

~~~~~(생략)

   

이제 게임센터에 접속하고, 점수를 보여줄 준비는 끝났다.

프로그램을 실행해보면 다음과 같이 게임센터에 접속하는 모습을 볼수 있다.





2.3. 게임센터로 점수와 목표달성도를 보내보자


이제 자신의 프로그램 플로우에 따라 게임센터 서버로 점수와 목표달성도를 보내보는 메소드를 구현해보자.

사실 보내는 메소드는 위에 구현해놨기 때문에 테스트 메소드로 사용법만을 적어본다.


프로그램에서 적당한 위치에 (실제로 게임센터로 데이터를 보내야하는 클래스에서) 테스트 메소드들을 만들었다.

//테스트 메소드들

-(IBAction)test1:(id)sender {

    //이렇게 보내면 er10 이라는 ID를 가지는 목표 달성도가 25%가 찍히게 된다.

    [AppUtils sendAchievementWithIdentifier:@"er10" percentComplete:25.0f];

}


-(IBAction)test2:(id)sender {

    //이렇게 보내면 er10 이라는 ID를 가지는 목표 달성도가 완료되게 된다.

    [AppUtils sendAchievementWithIdentifier:@"er10" percentComplete:100.0f];

}


-(IBAction)test3:(id)sender {

    //이렇게 보내면 sit 이라는 ID를 가지는 목표 달성도가 완료되게 된다.

    [AppUtils sendAchievementWithIdentifier:@"sit" percentComplete:100.0f];

}


- (IBAction)testpoint:(id)sender {

    int r = rand() % 1000;

    //이렇게 보내면 점수판에 1000사이의 정수가 랜덤으로 기록되게 된다.

    [AppUtils sendScoreToGameCenter:r];


    //이렇게 보내면 목표달성도가 리셋되게 된다.

    [AppUtils resetAchievements];

}

 
 





2.4. 점수판도 띄워보고 목표달성판도 띄워보자!


메뉴또는 About 화면등.. 원하는 위치에 버튼을 만들고 누르면 게임센터의 점수판과 목표달성판이 나오도록 해보자.

나는 AppInfoViewController 라는 클래스에 코딩을 해놨다.

 


포인트 순위표, 목표 달성이란 버튼을 만들고 각각 Touch Up Inside 이벤트에 openLeaderBD 라는 점수판을 띄우는 메소드와 openArchivementBD 라는 목표달성판을 띄우는 메소드를 만들었다. (Archivement 는 오타인데 만들고 나서 나중에 수정하기 귀찮아서 그냥 사용 -_-)



AppInfoViewController.h

#import <GameKit/GameKit.h>

@interface AppInfoViewController : UIViewController<GKLeaderboardViewControllerDelegateGKAchievementViewControllerDelegate>{ 

//점수판,목표달성판을 띄우는 뷰컨트롤러 딜리게이트 구현

}


/////////////////Geunwon,Mo : GameCenter 추가 start 


- (IBAction)openLeaderBD:(id)sender; //점수판을 띄운다

- (IBAction)openArchivementBD:(id)sender; //목표달성판을 띄운다


- (void) showLeaderboard; //실제로 점수판을 띄우는 부분 구현 메소드

- (void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController;//점수판이 닫힐때 호출되는 메소드

- (void) showArchboard; //목표달성판을 띄우는 부분 구현 메소드

- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController;//목표달성판이 닫힐때 호출되는 메소드


/////////////////Geunwon,Mo : GameCenter 추가 end 


@end

 

AppInfoViewController.m

~~~(생략)


/////////////////Geunwon,Mo : GameCenter 추가 start /////////////


///////////////// 점수판

// 점수판 버튼이 눌리면 호출된다.

- (IBAction)openLeaderBD:(id)sender{ 

    NSLog(@"open leader board");

    [self showLeaderboard]; // 실행~

}


- (void) showLeaderboard {

    GKLeaderboardViewController *leaderboardController = [[[GKLeaderboardViewControllerallocinit]autorelease];

    if (leaderboardController != nil) {

        // 레더보드 델리게이트는 나임

        leaderboardController.leaderboardDelegate = self;


        // 레더보드를 현재 뷰에 모달로 띄운다.

        [self presentModalViewController:leaderboardController animatedYES];

    }

}


// 레더보드 델리게이트를 구현한 부분. 닫힐때 호출된다.

- (void) leaderboardViewControllerDidFinish:(GKLeaderboardViewController *)viewController {

    [self dismissModalViewControllerAnimated:YES]; //점수판 모달뷰를 내림

    // 추가적으로 자신의 어플에 맞게 구현해야할것이 있으면 한다.

}


///////////////// 목표달성. (점수판 구현과 방법은 똑같음)

// 목표달성판 버튼이 눌리면 호출된다.

- (IBAction)openArchivementBD:(id)sender {

    NSLog(@"open archivement board");

    [self showArchboard];

}


- (void) showArchboard {

    GKAchievementViewController *archiveController = [[[GKAchievementViewController alloc]initautorelease];

    

    if (archiveController != nil) {

        

        archiveController.achievementDelegate = self;


        [self presentModalViewController:archiveController animatedYES];

        

    }

}


- (void)achievementViewControllerDidFinish:(GKAchievementViewController *)viewController{

    [self dismissModalViewControllerAnimated:YES];

}


////////////////////Geunwon,Mo : GameCenter 추가  //////////////

 

따로 주의해야할점은 점수판과 목표달성판은 UIView 위에 띄워주게 되어있는데 지금 작업한 어플은 UIView에서 도는 어플이라 상관없지만 cocos2d 나 기타 openGLES 등을 이용한 어플이라면 UIView 를 하나 띄워주고 그 뷰의 모달로 띄워주어야 화면에 표시가 될것이다. (해보지는 않았음-_- 구글링 추천)



이제 누르면 다음과 같이 점수판과 목표달성판이 이쁘게 뜬다.





끗.


Posted by 모근원
  1. 감사합니다!. 화이팅!

  2. 비밀댓글입니다

    • 익명 2011.04.26 08:59

      비밀댓글입니다

    • 음. 해당 부분은 제가 잘 모르겠네요.
      도움이 못 되서 죄송합니다.
      APP Identify 등으로 검색해보시면 될것 같네요.
      설치를 안하고 포인트를 주게 하려면
      설치 버튼을 누를때 메소드를 호출 시켜주면 될것 같네요.

  3. 비밀댓글입니다

  4. 양준영 2011.05.10 18:33

    안녕하세요.
    블로그와서 좋은 정보 얻고 가는 아이폰 초보 개발자입니다.
    개발하면서 모르는 것도 많고, 도움이 좀 필요할 거 같아서 그러는데....ㅠ
    메일 주소 좀 알려주시면 안될까요?ㅠ

    • 뭐 딱히 비밀은 아니지만 PDF파일안에 있습니다;;
      도움을 드릴수 있을지는 모르겠네요 ^^;
      퇴근하면 키보드는 거의 만지지 않거든요.
      양해부탁드립니다.

  5. 그건일 2011.05.25 11:26

    잘읽었습니다.
    고맙습니다.

  6. 좋은 자료 감사합니다. 그런데 테스트용 어플을 iTunes Connect에 어떻게 등록하죠? 애플 영문 도움말에 보니까 game center servers in the sandbox environment에서 테스트하라고 하는데.. 어떻게 해야 하는지 알려주시면 감사하겠습니다..

  7. 아이폰4.1, 아이패드4.2.1때는 잘 썼는데
    둘다 4.3.3으로 업뎃하고나서 안되네요
    탈옥해서 그런건지; 다른게임은 잘 되는데
    개발중인 게임을 디바이스로 테스트할때만 로그인이 안되네요

    • 엇 이상하네요
      저거 테스트 할때 4.3.3 이었습니다.
      탈옥은 안되어있었구요.
      지금은 5.0이라 테스트를 못해보겠네요;;
      해결하시길 바랍니다 :)

  8. 잘 보았습니다.
    그런데 궁금한점이 스코어 갱신시 노티뜰때 저는 랜드스케이프라이트 방향이거든요
    그러다보니 같이 회전된 뷰에 맞추는게아니라 무조건적인 기기방향에 맞게 나오더라고요 제 뷰에 맞춰서 회전을 시키려면 어떤식으로 조작을 해야할까요?

  9. 좋은 자료 잘 보고 갑니다! :)

  10. 사랑합니다.

  11. 아칙이 2011.12.13 10:32

    모근원님 ㅠㅠ
    xcode 4 에선 왜 안될까요 ㅠㅠ
    autorelease를 지우고 실했했는데 점수가 안올라가네요 ㅠ 에러는 안뜨는데 ㅠㅠ
    어떻게 해야 할까요 ㅠ

    • ARC를 사용하시나보군요..
      그렇다고 동작안하는건 문제가 있을텐데요 ㅠ 제가 지금 확인해볼수가 없네요 흑흑 죄송합니다 ㅠ

  12. 와, 필요하던 정보였는데.. 정말 감사합니다 !

  13. 안녕하세요 좋은 자료 감사합니다!
    설명도 잘 되있어서 쉽게 따라왔습니다.

    그런데 노티를 랜드스케이프로 띄우는 방법은 없을까요?
    제 어플은 랜드스케이프인데, 노티는 포트레이트로만 뜨네요 ㅠㅠ
    구글링해도 제대로된 답변이 없네요

    • 해당 프로젝트를 지워버려서 없습니다만;; 아마 keyWindow 에 올리는것이면 transform = CGAffineTransformRotate(CGAffineTransformIdentity, M_PI * 1/2);
      [[AppSetting sharedAppSetting].backgroundView setTransform:transform];

      요런식으로 뷰 자체를 돌려주셔야 할것 같네요.

    • 와.. 해결 2012.07.25 11:32

      6시간 동안 개고생하다가 구글링 해서 한줄로 해결 ㅡㅡ...
      GKAchievementHendler.m 에서 -(id)init 매소드에

      _topView = [[UIApplication sharedApplication] keyWindow]; 를 _topView = [[[[UIApplication sharedApplication] keyWindow] subviews] objectAtIndex:0]; 로 변경하니 되네요.... 역시 문제의 답은 구글링인듯....

  14. 바다로 2012.05.24 10:44

    안녕하세요. 쉽게 설명해주셔서 어려움 없이 저도 구현했습니다.

    그런데.. 제가 기존에 앱스토어에 등록된 앱의 다음버전 부터 게임센터를 추가하려고 하는데 "Game Center에서 이 게임을 인식할 수 없습니다" 라는 메세지가 뜨더라구요.

    혹시 이런 메세지를 보신적이 있으신가요?

    구글링해서 답을 찾아보니 기존에 설치되어있는 앱을 삭제하고 다시 설치하면 된다고는 하는데,
    그럼 기존 유저들이 모두 재설치를 해야하는건지, 아니면 이 문제는 샌드박스에서만 나타나는건지 궁금해서 혹시 이런 경험이 있으신지 여쭤봅니다.

    • 제가 지금은 해볼수가 없어서 답변을 드릴수가 없네요 ^^;
      잘 해결하시길 바랍니다.
      저는 그런 경험은 없었지만 게임센터 등록하려고 별별 방법을 다 쓰긴했었던것 같습니다.
      테스트 때문에요.


COCOSDenshion (of cocos2d 0.99.5) 의 SimpleAudioEngine 믿고 배경음을 출력했었다.
시뮬레이터에서 잘 되고~ 아이팟 터치 2세대에서 잘 되고~

그런데!! iPhone 4에서만 배경음악이 출력이 안되는것~! (효과음 effect 출력은 잘 되고있는데?!)
로그를 찍어보니 파일의 위치를 읽어오지 못하고 있었다.
참고로 한 Sample 의 TomTheTurret 도 마찬가지의 버그를 내고있었고..
버그인지.. cocos2d 라이브러리를 직접 수정하다가. 곧 업데이트가 될것 같아서 원복하고..
그냥 임시로 업데이트될때까지 SimpleAudioEngine 에서 배경음 재생 실패할 경우 AVAudioPlayer 를 이용해서 재생하도록 했다.
그리고 Fadein/out 시켜주는 메소드 하나 추가하고..
결과는 기종에 관계없이 배경음이 자~알 출력된다.
사운드 엔진은 싱글턴으로 프로그램내에서 어디서든지 불러다 쓸수있게 했다.

SimpleAudioEngine *soundEngine_;



//-- 이 아래에는 AVAudioPlayer를 위한 멤바들.

BOOL isAVAudioPlayer; //한번이라도 AVAudioPlayer 이용하여 배경음을 재생하면 셋팅된다.

//차선책으로 쓰는 AVAudioPlayer

AVAudioPlayer *bgmPlayer;

CGFloat fadeAmt; //Fadeout 감소값.

CGFloat fadeDesc; //Fadein 목표값.

요러한 멤버객체가 인터페이스에 선언이 되어있다 치고..

-(SimpleAudioEngine *) soundEngine

요런식으로 심플 오디오 엔진을 리턴하는 메소드가 있다 하자..

객체 init 해줄때 초기화 꼼꼼히 해주고..

isAVAudioPlayer = NO;

fadeAmt = 0;


dealloc  해줄땐 AVAudioPlayer 로 배경음 재생중이면 꺼주고 죽여주자.

if (self.bgmPlayer != nil) {

[self stopBGMwithAudioPlayer];

}




발로짠 오디오 플레이어 부분.

//배경음 재생을 시작한다.

-(void)playBGMwithAudioPlayer:(NSString*)filename ext:(NSString*)ext volume:(CGFloat)vol{

if (self.isSoundOn) {

[self stopBGMwithAudioPlayer];

if(self.bgmPlayer == nil){

self.bgmPlayer = [self createAudioPlayer:filename ext:ext volume:vol];

//-1 무한반복

self.bgmPlayer.numberOfLoops = -1;

}

[self.bgmPlayer play];

}

}


-(void)stopBGMwithAudioPlayer{

if (self.isSoundOn && self.bgmPlayer != nil) {

NSLog(@"AVAudioPlayer 스탑!");

[self.bgmPlayer stop];

// self.bgmPlayer.currentTime = 0; //rewind

self.bgmPlayer = nil;

}

}



//오디오 플레이어를 만든다.

-(AVAudioPlayer*)createAudioPlayer:(NSString*)filename ext:(NSString*)ext volume:(CGFloat)vol{

NSString *audioPath = [[NSBundle mainBundle]pathForResource:filename ofType:ext];

NSLog(@"새로운 AVAudioPlayer 생성 %@.%@ (%f%%)",filename,ext,vol);

AVAudioPlayer *tmpAudioPlayer = [[AVAudioPlayer alloc]initWithContentsOfURL:[NSURL fileURLWithPath:audioPath] error:nil];

tmpAudioPlayer.numberOfLoops = 0;

tmpAudioPlayer.volume = vol;

//소리를 위해 버퍼에 로딩

[tmpAudioPlayer prepareToPlay];

isAVAudioPlayer = YES;

[tmpAudioPlayer autorelease];

return tmpAudioPlayer;

}



//음악을 서서히 죽여준다.

-(void)fadeoutBGMwithAudioPlayer{

    if (self.bgmPlayer!=nil && self.bgmPlayer.volume > 0.01f) {

//2초정도 소리를 줄여주기 위하여

if (fadeAmt == 0) fadeAmt = self.bgmPlayer.volume/20;

        self.bgmPlayer.volume = self.bgmPlayer.volume - fadeAmt;

        [self performSelector:@selector(fadeoutBGMwithAudioPlayer) withObject:nil afterDelay:0.1f];

} else {

NSLog(@"fadeOut finish");

fadeAmt = 0;


[self stopBGMwithAudioPlayer];

}

}



//음악을 서서히 살려준다.

-(void)fadeinBGMwithAudioPlayer{

//NSLog(@"fadeIn %f amount %f desc %f",self.bgmPlayer.volume,fadeAmt,fadeDesc);

    if (self.bgmPlayer!=nil && self.bgmPlayer.volume <= fadeDesc) {

//2초정도 소리를 줄여주기 위하여

if (fadeAmt == 0) fadeAmt = fadeDesc/20;

        self.bgmPlayer.volume = self.bgmPlayer.volume + fadeAmt;

        [self performSelector:@selector(fadeinBGMwithAudioPlayer) withObject:nil afterDelay:0.1f];

} else {

NSLog(@"fadeIn finish");

fadeAmt = 0;

}

}


그리고 SimpleAudioPlayer 를 같이 쓰면서 배경음 재생 실패하면 바로 AVAudioPlayer 를 이용.

//BGM재생.

-(void) playBGM:(NSString*)filename ext:(NSString*)ext volume:(CGFloat)vol{

if (self.isSoundOn){

//soundEngine

if (!isAVAudioPlayer && [self soundEngine] != nil) {

NSLog(@"soundEngine 으로 배경음 재생 시도.");

[self soundEngine].backgroundMusicVolume = vol;

[[self soundEngine] playBackgroundMusic:[[NSBundle mainBundle] pathForResource:filename ofType:ext] loop:YES];

}

NSLog(@"soundEngine : isBackgroundMusicPlaying (%d), isAVAudioPlayer(%d)",[[self soundEngine] isBackgroundMusicPlaying],isAVAudioPlayer);

if (isAVAudioPlayer || [self soundEngine] == nil || ([self soundEngine] != nil && ![[self soundEngine] isBackgroundMusicPlaying])) {

//AudioPlayer

NSLog(@"soundEngine 으로 배경음 재생 실패하여 AVAudioPlayer 시도.");

[self playBGMwithAudioPlayer:filename ext:ext volume:vol];

}

}

}


-(void) fadeinBGM:(NSString*)filename ext:(NSString*)ext volume:(CGFloat)vol{

if (self.isSoundOn){

//soundEngine

if (!isAVAudioPlayer && [self soundEngine] != nil) {

NSLog(@"soundEngine 으로 배경음 페이드 재생 시도.");

[self soundEngine].backgroundMusicVolume = 0;

[[self soundEngine] playBackgroundMusic:[[NSBundle mainBundle] pathForResource:filename ofType:ext] loop:YES];

[CDXPropertyModifierAction fadeBackgroundMusic:2.0f finalVolume:vol curveType:kIT_SCurve shouldStop:NO];

}

if (isAVAudioPlayer || [self soundEngine] == nil || ([self soundEngine] != nil && ![[self soundEngine] isBackgroundMusicPlaying])) {

//AudioPlayer

NSLog(@"soundEngine 으로 배경음 재생 실패하여 AVAudioPlayer 페이드 재생 시도.");

fadeDesc = vol;

[self playBGMwithAudioPlayer:filename ext:ext volume:0];

[self fadeinBGMwithAudioPlayer];

}

}

}


-(void) stopBGM{

if (self.isSoundOn){

if (isAVAudioPlayer) {

[self stopBGMwithAudioPlayer];

} else {

if ([self soundEngine] != nil){

[[self soundEngine] stopBackgroundMusic];

}

}

}

}


-(void) fadeoutBGM {

if (self.isSoundOn) {

if (isAVAudioPlayer) {

[self fadeoutBGMwithAudioPlayer];

} else {

if ([self soundEngine] != nil){

//2 페이드 아웃.

[CDXPropertyModifierAction fadeBackgroundMusic:2.0f finalVolume:0.0f curveType:kIT_SCurve shouldStop:YES];

}

}

}

}


끗. (이랬는데 뭔가 잘못써서 SimpleAudioEngine 에서 출력이 안된거라면 대략 난감.. 삽질의 향기가..)


- (덧) COCOS 2D 1.0rc 버전에서는 수정되었음 -_-......... 
Posted by 모근원

상황 1 : 
SuperScene 이라는 상위클래스에서 private 변수로 CGPoint winSize 라는 변수를 생성해 두었음.

//  SuperScene.h

...

@interface SuperScene : CCScene {

CGSize winSize; //윈도우 사이즈

}

...


상황 2 : 
이 SuperScene 을 상속 받은 다른 클래스들에서는 상위 클래스에서 선언한 winSize 변수에 자유롭게 접근이 가능함. 이렇게 구현된 클래스가 수십개가 있는데 문제가 없었다.

그런데 SuperScene을 상속받은 수많은 클래스 중에서 유독 한 클래스에서 선언하지 않았다고 에러.. 
뭔가가 잘못되었음. (이밖에 상위 클래스인 SuperScene 에서 선언한 변수들은 죄다 에러)

상속받은 클래스에서 변수를 선언하려고하면 중복선언이라고 에러..





해결책 : 
@property 와 @synthesize 를 구현한 멤버변수가 없으면 엄한데서 오류가 나오기 시작한다!!!
내 경우엔 BattleScene 이란 하위 클래스(SuperScene을 상속받은..) 에서 @property 로 CurrentWeapon 이라는 멤버 변수를 보내주고 @synthesize 로 구현까지 해주었는데 정작.. CurrentWeapon 이라는 멤버변수를 선언하지 않았다;;;

- 이렇게 되어있으면 문제.. 정작 변수 선언이 되어있지 않았다.

@interface BattleScene : SuperScene {

}


@property (nonatomic, retain) CCSprite* currentWeaponMark;

@synthesize currentWeaponMark;


- 요렇게 해주거나 변수가 필요없으면 @property 와 @synthesize 를 삭제한다.

@interface BattleScene : SuperScene {

CCSpritecurrentWeaponMark;

}


@property (nonatomicretain) CCSprite* currentWeaponMark;

@synthesize currentWeaponMark;

Posted by 모근원

2011년 새해도 밝았고 앱을 만들어 앱스토어에 올리자! 라는 명목으로 맥을 구입한지도 3년째..
그간 맥북 기변에 업그레이드만 줄창 하다가 올해 목표는 진심으로 앱스토어에 앱을 올리는것으로 정했다.

처음엔 유용한 어플을 만들어 올릴까 했는데 눈이 점점 높아져서 어릴적부터 만들어보고 싶었던 게임을 만들기로 했다.
생각해보면 프로그래밍을 처음 배우기 시작했던것도 게임을 만들어보고 싶어서였었는데.. 
그냥 그렇게 10년도 넘게 훌쩍 지나가버렸다.

게임 그래픽은 죽마고우인 민태와 같이 작업하기로 하고 기획하고 기본 메소드들 만들기 시작하는데 하...
이거 cocos2d 라는 게임엔진이 상당히 잘 되어있다.
어플제작만 하고 게임제작은 난생 처음해보는 나도 공부한지 3일만에 쉬운 게임정도는 간단히(실은 그렇게 간단하지 않고 노가다가 필요하지만..) 만들수 있겠더라.

하여간 블로그에 공부하면서 개발하면서 얻은 노하우와 게임제작 기법등을 정리해 올려보기로 했다.
반년이내에 완성해서 앱스토어에 진출하리라~

*사진은 전투씬에서 충돌검사를 테스트하면서 찍은 스크린샷.
Posted by 모근원

- 이번 글은 보기좋게 PDF로 첨부합니다.




- 개인적인용도로 요약한 글이라 글에서는 경어체를 사용하지 않습니다. 글 읽으시는데 참고부탁드립니다.

- Mac의 Pages 로 작성한 후 블로그에 포스팅하려니 서식이 다 깨졌네요.

   PDF 파일로 보는것이 보기 좋습니다.


저번엔 안드로이드용 위치기반 지점찾기 (LBS)를 구현하였고, 이번에 아이폰용 뱅킹어플을 만들면서 아이폰용도 지점찾기를 어플로 구현할 필요가 생겼다.


이번엔 계속 써와서 익숙한 Java 가 아니라 Objective C 여서 시작하기가 막막했다. 배우면서, 삽질하며 완성시킨거라 버그도 있을것이고 여러부분에서 미숙한 점이 있을테지만 마찬가지로 까먹지 않기 위하여 정리를 해둔다.


1. 프로젝트에 프레임웍 추가하기.

프로젝트의 프레임웍에서 마우스 오른쪽버튼 (또는 옵션클릭)을 하여 프레임웍을 추가해준다.

사용자 위치정보를 가져올 CoreLocation.framework 와 지도표시에 필요한 MapKit.framework 을 추가해준다.


추가가 된것을 확인하면 성공.










2. 뷰에서 사용할 마커(어노테이션) 준비하기.


지도 앱들을 보면 다음과 같은 핀이 있는데 이것이 안드로이드에서는 마커, iOS에서는 어노테이션이라고 불리우는 드랍핀이다. 


그냥 써도 되지만 지점찾기 앱에서는 각 마커마다 지점의 정보를 가지고 있기

때문에 MKAnnotation 을 구현하여 커스텀 어노테이션을 만들어 쓰기로 했다.



//  BranchMarker.h

// 마커(어노테이션) 쓰일 객체.


#import <Foundation/Foundation.h>

#import <MapKit/MKAnnotation.h>


@interface BranchMarker : NSObject <MKAnnotation>{

//요거 세개는 어노테이션에 필수로 구현해줘야 동작한다.

CLLocationCoordinate2D coordinate;

NSString *title;

NSString *subtitle;

// 아래는 추가로 필요해서 변수 준비.

NSString *bussBrNm; //영업점명

NSString *bussBrTelNo; //영업점 전화번호

NSString *bussBrAdr; //영업점주소 (찾아오시는길)

NSString *trscDrtm; //거래시간

NSString *bussBrAdr2; //영업점주소 (주소)

NSString *markerType; //마커 타입 (0:지점, 1:ATM)

}


@property (nonatomic,assign) CLLocationCoordinate2D coordinate;

@property (nonatomic,copy) NSString *title;

@property (nonatomic,copy) NSString *subtitle;


@property (nonatomic,retain) NSString *bussBrNm;

@property (nonatomic,retain) NSString *bussBrTelNo;

@property (nonatomic,retain) NSString *bussBrAdr;

@property (nonatomic,retain) NSString *trscDrtm;

@property (nonatomic,retain) NSString *bussBrAdr2;

@property (nonatomic,retain) NSString *markerType;


@end

헤더에서는 coordinate, title, subtitle 을 필수로 구현해줘야 MKAnnotation 이 멀쩡히 돌아간다.


//  BranchMarker.m

#import "BranchMarker.h"


@implementation BranchMarker

@synthesize coordinate, title, subtitle;

@synthesize bussBrNm,bussBrTelNo,bussBrAdr,trscDrtm,bussBrAdr2,markerType;


-(void) dealloc{

[title release];

[subtitle release];

[super dealloc];

}


@end

구현파일에서는 특별히 구현할것이 없고 synthesize 만 충실히 해주도록 한다.



3. 뷰컨트롤러 준비하기.

이제 실제 지도를 구현해본다. 이번 어플에서는 크게 다음과 같이 네개의 뷰가 겹쳐져 있다.

맨 아래에 지도를 표시하는 MKMapView 가 깔리고 그 위로 서브뷰로 아이콘 버튼들이 있는 툴바,

그리고 툴바위에 역 지오코딩 (위도, 경도를 가지고 주소를 추적해내는 기술) 한 스트링이 UILabel 로 뿌려지고, 마지막으로 그 위에 어플이 로딩상태일때 로딩을 표시할 스피너가 올려져있다.


//  BranchMapViewController.h

// 지점찾기 컨트롤러.


#import <UIKit/UIKit.h>

#import <MapKit/MapKit.h>

#import <CoreLocation/CoreLocation.h>


//위치관리자, 맵뷰, 그리고 리버스 지오코더 딜리게이트를 구현한다.

@interface BranchMapViewController : UIViewController <CLLocationManagerDelegate , MKMapViewDelegate, MKReverseGeocoderDelegate>{

NSString *searchType; //지점,ATM 검색 타입

MKMapView *mapView; //지도

//,경도를 가지고 해당위치의 주소를 가지고 오는 리버스지오코더

MKReverseGeocoder *reverseGeocoder

//위지관리자. GPS,wifi 등으로 현재 기기의 위치를 가져온다.

CLLocationManager *locationManager;

CLLocation *lastScannedLocation; //마지막으로 검색된 위치를 저장할 객체.

UIActivityIndicatorView * spinner; //화면의 로딩 스피너.

UILabel *geoLabel; //툴바에 리버스지오코더의 결과를 표시한다.

}


@property (retain, nonatomic) NSString *searchType;

@property (retain, nonatomic) MKMapView *mapView;

@property (nonatomic, retain) MKReverseGeocoder *reverseGeocoder;

@property (nonatomic, retain) CLLocationManager *locationManager;

@property (nonatomic, retain) CLLocation *lastScannedLocation;

@property (nonatomic, retain) UIActivityIndicatorView * spinner;

@property (nonatomic, retain) UILabel *geoLabel;


//뷰컨트롤러를 만들때 검색타입을 지정한다. BRANCH/ATM

- (id)initWithShowType:(NSString *)showType;  

//지점정보를 HTTP통신으로 가지고 온다.
- (void)getBranchDataWithLocation:(CLLocation *)location; 

@end


메인 구현파일이라 엄청길다.

//  BranchMapViewController.m

#import "BranchMapViewController.h"

#import <MapKit/MapKit.h>

#import <CoreLocation/CoreLocation.h>

#import "BranchMarker.h"

#import "BranchMapGetDataAction.h"


@implementation BranchMapViewController


@synthesize searchType;

@synthesize mapView,reverseGeocoder,geoLabel;

@synthesize locationManager;

@synthesize lastScannedLocation;

@synthesize spinner;


- (id)initWithShowType:(NSString *)showType {

if ((self = [super init])) {

        // Custom initialization

self.searchType = showType;

    }

NSLog(@"initWithShow %@",self.searchType);

    return self;

}


//이미지로 커스텀 뷰를 만들어준다.

//_normalImg : 버튼 이미지, _touchImg : 눌럿을때 바뀔 이미지, _width : 이미지버튼의 가로길이, _height : 이미지버튼의 세로길이 , _sel : 버튼눌렀을때 액션

-(UIButton*) createCustomImageButtonWithNormalImgNm:(NSString*)_normalImg

  andTouchImg:(NSString*)_touchImg andWidth:(float)_width

andHeight:(float)_height andSEL:(SEL)_sel{

// 버튼 배경에 사용할 이미지 준비.

    UIImage *normalImage = [UIImage imageNamed:_normalImg];

    UIImage *touchImage = [UIImage imageNamed:_touchImg];

    

    // 버튼 생성 

//x,y,width,height

    CGRect buttonRect = CGRectMake(0.0f, 0.0f, _width, _height); 

    UIButton *button = [[[UIButton alloc

initWithFrame:buttonRect] autorelease];

    // 버튼의 배경 이미지 설정

    [button setBackgroundImage:normalImage forState:UIControlStateNormal];

    [button setBackgroundImage:touchImage forState:UIControlStateHighlighted];

    

    // 버튼에 액션 설정

[button addTarget:self action:_sel

forControlEvents:UIControlEventTouchUpInside];


return button;

}


- (void)viewDidLoad {

    [super viewDidLoad];

//searchType 널탕이 들어오면 기본적으로 지점 검색으로 한다.

if (self.searchType == nil) self.searchType = @"BRANCH";

//위치 관리자를 초기화한다.

self.locationManager = [[[CLLocationManager alloc] init] autorelease];

//딜리게이트는 self 설정후 하단에서 딜리게이트 구현.

self.locationManager.delegate = self;

//측정방법은 가장 좋게.

self.locationManager.desiredAccuracy = kCLLocationAccuracyBest

//2000m 이상 위치가 변경되면 노티를 .

self.locationManager.distanceFilter = 2000.0f

    [self.locationManager startUpdatingLocation]; //현재위치 가져오기 시작~

//지도 뷰를 만든다.

//뷰의 크기만큼 지도를 채운다.

mapView = [[MKMapView alloc] initWithFrame:self.view.bounds];

mapView.showsUserLocation = YES; // 위치 표시.

[mapView setMapType:MKMapTypeStandard]; //지도 형태는 기본.

[mapView setZoomEnabled:YES]; //줌가능

[mapView setScrollEnabled:YES]; //스크롤가능

mapView.delegate = self; //딜리게이트 설정 (anotation 메소드를 구현한다.)

MKCoordinateRegion region;

MKCoordinateSpan span; //보여줄 지도가 처리하는 넓이 정의.

span.latitudeDelta = 0.02; //숫자가 적으면 좁은영역 까지 보임.

span.longitudeDelta = 0.02;

CLLocationCoordinate2D location = mapView.userLocation.coordinate;

//위치정보를 못가져왔을때 기본으로 보여줄 위치.

location.latitude = 37.566275; //37.490481 이건 우리집

location.longitude = 126.981794; //126.857790

region.span = span; //크기 설정.

region.center = location; //위치 설정.

[mapView setRegion:region animated:TRUE]; //지도 뷰에 지역 설정.

[mapView regionThatFits:region]; //지도 화면에 맞게 크기 조정.

[self.view addSubview:mapView]; //서브 뷰로 지도를 추가함.

//하단에 버튼들 toolbar 추가

//현재 뷰의 크기를 가져와서 상단 바의 길이가 조정되면 하단 바가 잘리는것을 방지하기 위함.

float heightPos = self.view.bounds.size.height

UIToolbar *toolbar = [[UIToolbar alloc

  initWithFrame:CGRectMake(0.0, heightPos - 50.0f , 320.0, 50.0)]; toolbar.barStyle = UIBarStyleBlackTranslucent; //툴바스타일은 까만 투명색

// 영역 잡아주는 버튼아이템. 왼쪽에 빈 영역 두고, 오른쪽으로 버튼들을 배치하기위함.

UIBarButtonItem *flexibleSpace = [[UIBarButtonItem alloc]

  initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace

  target:nil action:nil];

 

//이미지 커스텀 버튼.

UIBarButtonItem *hereBtn = [[UIBarButtonItem alloc]

   initWithCustomView:[self createCustomImageButtonWithNormalImgNm:@"here.png"

   andTouchImg:@"here_pressed.png" andWidth:40.0f andHeight:40.0f

   andSEL:@selector(setSearchTypeToHere)]]; //현위치

UIBarButtonItem *branchBtn = [[UIBarButtonItem alloc]

   initWithCustomView:[self createCustomImageButtonWithNormalImgNm:@"atm_btn.png" 

   andTouchImg:@"atm_btn_pressed.png" andWidth:40.0f andHeight:40.0f 

   andSEL:@selector(setSearchTypeToATM)]]; //ATM검색

UIBarButtonItem *atmBtn = [[UIBarButtonItem alloc]

   initWithCustomView:[self createCustomImageButtonWithNormalImgNm:@"hana_btn.png"

   andTouchImg:@"hana_btn_pressed.png" andWidth:40.0f andHeight:40.0f 

   andSEL:@selector(setSearchTypeToBranch)]]; //지점검색

//툴바 아이템 배치

toolbar.items = [NSArray

arrayWithObjects:flexibleSpace,hereBtn,atmBtn,branchBtn,nil];


//툴바를 뷰에 추가.

[self.view addSubview:toolbar];

//툴바에 쓰인 버튼들 릴리즈.

[flexibleSpace release];

[hereBtn release];

[branchBtn release];

[atmBtn release];

[toolbar release];

//화면스피너 셋팅. 로딩중을 표시하기 위함.

self.spinner = [[UIActivityIndicatorView alloc

initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];

//화면중간에 위치하기위한 포인트.

[self.spinner setCenter:CGPointMake(320.0f/2.0, 480.0f/2.0)]; 

[self.view addSubview:spinner]; //스피너를 뷰에 추가하고 필요시에 start

//geoCoder 라벨 셋팅. '서울시 송파구 신천동' 따위를 툴바에 표시한다

geoLabel = [[UILabel alloc

initWithFrame:CGRectMake(5.0, heightPos - 45.0f, 160.0, 40.0)];

geoLabel.backgroundColor = [UIColor clearColor];

geoLabel.highlighted = YES;

geoLabel.highlightedTextColor = [UIColor whiteColor];

geoLabel.shadowColor = [UIColor blackColor];

geoLabel.textColor = [UIColor whiteColor];

geoLabel.textAlignment = UITextAlignmentLeft;

geoLabel.numberOfLines = 2; //두줄 표시 가능.

[self.view addSubview:geoLabel]; //뷰에 라벨 추가.

//초기 환영 메세지.

UIAlertView *alert = [[UIAlertView alloc]initWithTitle:@"위치기반 지점찾기" message:@"위치정보를 가져오는데 기기,통신상태에 따라 시간이 걸릴수 있으며 일부 동작하지 않는 기기도 있습니다.\n\n하단의 아이콘을 이용하여 현재 지도가 표시하고 있는 지역을 중심으로 지점/ATM 검색하실 있습니다." delegate:nil cancelButtonTitle:nil

otherButtonTitles:@"확인",nil];

[alert show];

[alert release];

}


//검색 타입 ATM으로 셋팅.

-(void)setSearchTypeToATM{

//현재 지도가 위치하는곳을 중심으로.

CLLocation *customLocation = [[CLLocation alloc

initWithLatitude:mapView.centerCoordinate.latitude 

longitude:mapView.centerCoordinate.longitude];

self.searchType = @"ATM";

[self getBranchDataWithLocation:customLocation]; //HTTP 통신

[customLocation release];

}


//검색 타입 지점으로 셋팅.

-(void)setSearchTypeToBranch{

//현재 지도가 위치하는곳을 중심으로.

CLLocation *customLocation = [[CLLocation alloc

initWithLatitude:mapView.centerCoordinate.latitude 

longitude:mapView.centerCoordinate.longitude];

self.searchType = @"BRANCH";

[self getBranchDataWithLocation:customLocation]; //HTTP 통신

[customLocation release];

}


//현위치

-(void)setSearchTypeToHere{

[self.locationManager startUpdatingLocation];  //로케이션 메니저 다시 시작~

}


//문자열 치환 메소드. source : 원본, 찾을문자열, 바꿀문자열.

-(NSString*)replaceStrSource:(NSString*)sourceStr 

strFrom:(NSString*)_from strTo:(NSString*)_to{

NSMutableString *mstr = [NSMutableString stringWithString:sourceStr];

NSRange substr = [mstr rangeOfString: _from];

while (substr.location != NSNotFound) {

[mstr replaceCharactersInRange: substr withString:_to];

substr = [mstr rangeOfString: _from];

}

return mstr;

}



//지도 데이터를 HTTP통신을 통해 받아와서 표시해준다.

- (void)getBranchDataWithLocation:(CLLocation *)location{

NSLog(@"getBranchDataWithLatitude:%f andLongitude:%f",

location.coordinate.latitude,location.coordinate.longitude);

//화면에 로딩스피너 스타트.

[self.spinner startAnimating];

//HTTP통신에 ContentProvide server 규격을 맞추기 위해, 위도,경도에서 콤마(.) 제거해서 보내야한다.

NSString *lat = [self replaceStrSource:

[NSString stringWithFormat:@"%f",location.coordinate.latitude]

strFrom:@"." strTo:@""];

NSString *lng = [self replaceStrSource:

[NSString stringWithFormat:@"%f",location.coordinate.longitude]

strFrom:@"." strTo:@""];

NSString *range = @"3000"; //기본 3Km반경 지점을 검색해 오게 만든다.

NSString *sType = @"0";

//ATM = 1, 지점 = 0

if ([self.searchType isEqualToString:@"ATM"]) sType = @"1";

else sType = @"0";


//HTTP통신으로 지점정보 가져오는 액션 초기화.

BranchMapGetDataAction *getAction = [[BranchMapGetDataAction alloc

initWithSearchType:sType andReqLat:lat andReqLng:lng andReqRange:range];

//HTTP통신으로 지점정보를 가져온다.

NSMutableArray *branchMarkerAry = [getAction getData];

//마커를 새로 찍기전에 기존에 지도에 있던 마커(annotation) 전부 지운다.

NSMutableArray *toRemove = [NSMutableArray arrayWithCapacity:1];

for(id annotation in mapView.annotations){

if (annotation != mapView.userLocation){

[toRemove addObject:annotation];

}

}

NSLog(@"remove %d annotations.",[toRemove count]);

[mapView removeAnnotations:toRemove];

//받아온 마커(annotation) 맵에 찍어낸다.

NSLog(@"branch marker count : %d",[branchMarkerAry count]);

if([branchMarkerAry count] > 0){

for (BranchMarker* marker in branchMarkerAry){

if (marker != nil) [mapView addAnnotation:marker];

}

}


//reverseGeocoding 시작.

self.reverseGeocoder = [[[MKReverseGeocoder alloc

initWithCoordinate:location.coordinate] autorelease];

    reverseGeocoder.delegate = self;

    [reverseGeocoder start];

//화면의 로딩 스피너 없애기.

[self.spinner stopAnimating];


}


//메모리 부족을 받았을때.

- (void)didReceiveMemoryWarning {

    // Releases the view if it doesn't have a superview.

    [super didReceiveMemoryWarning];

    NSLog(@"branchmap memory warning.");

    // Release any cached data, images, etc that aren't in use.

}


// 내릴때.

- (void)viewDidUnload {

    

NSLog(@"branchmap viewDidUnload");

[self.locationManager stopUpdatingLocation];

self.locationManager = nil;

self.reverseGeocoder = nil;

self.mapView = nil;

self.searchType = nil;

self.lastScannedLocation = nil;

self.spinner = nil;

[super viewDidUnload];

}


//객체 내려갈때.

- (void)dealloc {

NSLog(@"branchmap dealloc");

//사용한 객체들 릴리즈.

[mapView release];

[reverseGeocoder release];

[locationManager release];

[searchType release];

[lastScannedLocation release];

[spinner release];

    [super dealloc];

}



#pragma mark MKMapViewDelegate


NSString *tempTelNo; //어노테이션의 더보기에서 전화걸기를 누를때 임시로 전화번호를 저장할 변수.


//맵의 어노테이션 (마커) 표시.

-(MKAnnotationView *)mapView:(MKMapView *)mV viewForAnnotation:(id<MKAnnotation>)annotation{

if (annotation==self.mapView.userLocation){

[mV.userLocation setTitle:@"현재 위치"]; //현재위치 마커에 표시할 타이틀.

return nil; //현재 위치 마커일경우 커스텀 마커를 사용하지 않는다.

}

//현재위치 마커가 아닐때에는 지점마커이다.

BranchMarker *mk = (BranchMarker *) annotation;

MKPinAnnotationView *dropPin = nil; //마커 준비

static