반응형

아이폰7부터 애플이 제대로 돌아서 이어폰잭을 없애버렸다.
애플4부터 애플 이외 다른 스마트폰은 사용해오지 않았지만
아이폰7 이후부터 난 주변에 아이폰 구매를 고민하는 지인들에겐 도시락 제조해가며 뜯어말리고 있다.

배터리가 하나임에도 불구하고 이어폰을 이용할 땐 충전을 못하고 그렇다고 콩나물 무선 블루투스 이어폰이 싸거나 무선 충전이 되지도 않는 개떡같은 폰이기 때문이다.


그래도 어쩌겠는가? 안드로이드는 못가겠으니 블루투스 이어폰을 알아보던김에 회사에서도 눈치채지 못하게 당당히 사용할 수 있으면서도 가격이 깡패인 대륙의 실수인 QCY Q26 블루투스 이어폰을 구입하게 되었다.



사진처럼 생각보다는 조금 크다.
귓속에 들어갈거란 예상과 달리 귀에서 튀어나오는 수준?



QCY블루투스 이어폰을 착용한 모습



검정콩알을 귀에 넣은듯한 모습이고, 착용한 느낌은 애플 이어폰보다 훨씬 착용감이 뛰어나다.
고개를 흔들어봐도 빠지지 않는다.



저 스펀지 때문이리라.

여하튼 아이폰7의 망할 이어폰 삭탈관직에 불편함을 느끼는 분들에게 선택할만한 블루투스 이어폰이라 생각된다.

음질도 뭐 쏘쏘
다만 양쪽 모두 된다면 더 괜찮을듯 싶다란 아쉬움은 존재한다.

참고로 페어링하려면 전원 오프 상태에서 전원을 누르고 있으면 파워온이 되고 계속 누르다보면 페어링이 뜬다.



이상 QCY Q26 블루투스 이어폰 살짝 리뷰 끝


반응형
Posted by Hippalus
,

반응형

구글맵과 CLLocationManager를 이용하여 위치기반 데이터를 수집중이었는데 일반적인 지도앱을 개발중이었는데

백그라운드 상태에서도 경로를 sqlite에 저장해야 하는 상황이었고 앱특성상 5시간 이상 수집을 해야만 했다.


발목을 잡고 태클을 이중 삼중으로 걸었던 부분은 앱 위치정보 사용 설정 부분이었는데 위치정보 사용법은 두가지가 존재한다.


Privacy - Location Always Usage Description (앱을 사용하지 않을때도 위치 수집)

Privacy - Location When In Use Usage Description (앱


도대체 Location Always Usage Description와 Location When In Use Usage Description 중 어떤걸 사용해야 하느냐였다.

찾아보니 Always Usage가 When In Use Usage보다 상위이기에 Always Usage를 쓰면 되고 다만 

Always Usage사용시 백그라운드 모드로 이동시 blue status bar가 나타나지 않는다란 설명도 알게 되었다.


하여 아무생각없이 Always Usage 썼고 잘 동작하였다.


그런데 이놈이 3시간만 지나면 무조건 리셋이 되어버리는 상황이 발생한다.

그것도 램 2기가인 아이폰7+에선 12시간이 지나도 잘 돌아가는 반면, 램 고자인 하위 기종에선 최대 아무리 버텨봐야 3시간~4시간이면 100% 앱이 리셋이 되어 앱실행시 지도화면이 아닌 초기화면으로 


이동되어 있었다.


질문글을 올려봐도, stackoverflow.com을 검색해 보아도 마땅한 답이 아닌 메모리 관리를 잘해야 한다란 답변들 밖에 들을 수 없었다.

메모리 모니터링을 해봐도 메모리가 누적되진 않았다.

혹시 구글맵의 Camera 이동 코드가 didupdate에 들어가 있어서 백그라운드 모드에서 호출되며 알지 못하는 문제 때문에 앱이 3시간 후 리셋되나? 싶어 그부분도 걷어봤지만 동일할 뿐 나아지지 않았


다.


정말 마지막 시도로 다른 상용 조깅앱인 runkeeper과 비교를 해보았더니 조깅앱은 하루가 지나도 잘만 동작하였다.

외관상 다른점은 딱 하나 blue status bar가 있다란 점.


blue status bar가 나타나게 하려면 Location Always Usage Description이 아닌 Location When In Use Usage Description을 사용하여야만 한다.


하여 기존 Privacy - Location Always Usage Description 대신 Privacy - Location When In Use Usage Description로 바꾸고 테스트를 하였더니 ㅡㅡ

6시간이 지나도 쌩쌩하게 잘만 동작함이 확인 되었다.




[결론]

장시간(3시간 이상)백그라운드 상태에서 계속 위치 정보 수집을 하려들 경우 

Privacy - Location When In Use Usage Description / requestWhenInUseAuthorization 사용함과 동시에

iOS9부터 제공하는 setAllowsBackgroundLocationUpdates를 사용하여야만 가능함.




[결론 부가 설명]

애플문서(https://developer.apple.com/reference/corelocation/cllocationmanager/1620551-requestalwaysauthorization)를 보면 

"When the user grants “Always” authorization to your app, your app can start any of the available location services while your app is running in the foreground or background."라는 문


구 때문에 마치 requestAlwaysAuthorization을 사용해야만 백그라운드에서 위치 정보 수집이 가능하다 착각하겠지만


애플문서(https://developer.apple.com/reference/corelocation/cllocationmanager/1620562-requestwheninuseauthorization)를 보면

(Apps cannot use any services that automatically relaunch the app, such as region monitoring or the significant location change service.) When started in the foreground, services 


continue to run in the background if your app has enabled background location updates in the Capabilities tab of your Xcode project.

즉 "앱이 지역 모니터링이나 중요한 위치 변경 서비스와 같이 앱이 자동으로 서비스를 실행하는건 못하지만 포그라운드에서 실행 후 백그라운드에서 실행 가능하도록 프로젝트를 설정한 경우 백그라


운드에서 계속 실행된다라" 적혀있기 때문에 프로젝트에 백그라운드 지원 설정만 한다면 백그라운드 상태에서도 제한 없이 위치 정보 수집이 가능하다.

오히려 시간 무제한 위치정보를 수집이 가능하다.

이해할 수 없는 점은 애플은 왜 requestAlwaysAuthorization를 만들어 놓고도 OS단에서 3~4시간이 지나면 무조건 리셋을 시켜대는 것일까란 점이다.





[장시간 백그라운드 상태에서 사용자의 위치정보를 수집하는 핵심 방법 정리]

1.프로젝트 설정

프로젝트 > Capabilities > Background Modes > Location update 체크




2.info.plist파일

Privacy - Location When In Use Usage Description 추가 후 적당한 문구 삽입

Privacy - Location Usage Description 추가 후 적당한 문구 삽입


3.소스에서 CLLocationManager 초기화 후 앱사용시에만 위치정보 수집을 하겠다와 백그라운드 상태에서도 위치정보 갱신을 하겠다는 코드 호출

locationManager.pausesLocationUpdatesAutomatically = NO; //자동으로 멈춤 방지


        if ([locationManager respondsToSelector:@selector(requestWhenInUseAuthorization)]) {

            [locationManager requestAlwaysAuthorization];

        }


        if ([locationManager respondsToSelector:@selector(setAllowsBackgroundLocationUpdates:)]) {

            [locationManager setAllowsBackgroundLocationUpdates:YES];

        }


그러면 이렇게 파랑 상태바가 출몰함

반응형
Posted by Hippalus
,

반응형

가령 텍스트박스의 이름이 TEXTBOX인 경우 

TEXTBOX에 Y라는 값을 jQuery로 넣는 코드


$('input[name="TEXTBOX"]').val('Y');

반응형
Posted by Hippalus
,

반응형

요즘 앱이 아닌 웹 위주로 개발을 하다보니 이젠 앱 만드는 법도 가물가물해진 상황에서 늘 그러하듯 애플의 엿같은 인증서 체계로 인해 또한번 골탕을 먹었다.

정확히 하자면 인증서 문제인줄 알고 매번 애매한 오류를 내뱉어 버리는 애플의 푸쉬 인증서 문제인줄 알고 인증서 다 갈아버리고 새로 만들어 돌려도 저렇게 계속 


오류내용 : Error Domain=3000 "응용 프로그램을 위한 aps-environment 인타이틀먼트 문자열을 찾을 수 없습니다.(NSCocoaErrorDomain Code=3000) 라는 오류를 내뱉어 버렸다.

진심 빡친다.

가뜩이나 꽈놓은 인증서 체계인데 도무지 어디서부터 해결을 해야할지....




정말 삥삥 돌아서 얻은 정답


xcode8부터 괴상한 파일 두개가 생겨있다.

이게 또 웃긴게 어떤 프로젝트엔 프로젝트명.entitlements로 하나만 생성되어 있다. 

어처구니 없는 애플짓

내가 만들지도 않았는데 entitlements파일을 재수없어서 일단 삭제 후 다시 만들거나 아니면 복사해서 문자열만 바꾸거나 등등을 해야 하는데

난 깔끔하게 삭제하고 새로 만든다.


만약 없을경우 만드는 방법은 프로젝트를 눌러 나오는 메뉴에서 iCloud나 Push Notifications 등을 설정할 수 있는 capabilities에서 Push Notifications를 보면 이렇게 되어있을것이다. Fix issue를 누르면 앞서 entitlements파일이 생성됨을 알 수 있다.


그리고 편집모드에서 (plist파일처럼) APS Environment을 추가하고 production 으로 넣어준다.



끝으로 Build Settings에 가서 code signing entitlements 부분에 debug와 release에 각각 좀전에 만든 environment를 지정해줘야 오류가 안생긴다.

이부분이 가장 중요하다.

워낙 많은 Setting항목들 때문에 All로 해둔 상태에서만 보이기 때문에 자칫 못찾을 가능성도 존재한다.

루트에 있으면 저렇게 루트 그대로 루트 밑에 다른 폴더에 만들었으면 경로를 적어주면 잘된다.



그리고 빌드하면 예전처럼 오류없이 푸시가 잘 받아진다.


3줄요약

1.Capabilities에서 push notification의 fix issue하자

2.entitlements생기면 value에 production을 입력하고 Build Settings에서 code signing entitlements에 경로 제대로 잡혀있는지 확인

3.망할 애플








반응형
Posted by Hippalus
,

반응형

CocoaPod로 라이브러리를 추가한 후 Undefined symbols for architecture arm64 : _OBJC_CLASS_$_해당클래스명 오류가 발생할 수 있다.

이런 링크 오류가 발생하면 난감해진다.

stackoverflow.com을 찾아봐도 /Users/유저/Library/Developer/Xcode/DerivedData/프로젝트/Build의 하위폴더를 날리라는 엄한 답만 나와있고 -_-


결국 찾은답이 의외로 간단하다.


Xcode의 좌측 프로젝트(Command+1)보기 화면의 하단에 Pods/Products로 가보면 해당 라이브러리가(라이브러리명.a 파일) 보인다.


누르고 우측탭을 보면 Pods-프로젝트과 함께 해당 외부클래스명이 보이는데 Pods-프로젝트의 체크박스에만 체크해주고 빌드하면 감족같이 에러가 사라짐을 확인할 수 있다.

이거 찾아내느라 2시간 넘게 고생 ㅡㅡ









반응형
Posted by Hippalus
,

반응형

HTML에서 파라메터(param) 받기



ASP나 JSP같은 동적웹페이지가 아닌 HTML자체에서 파라메터를 받기 위해선 javascript를 통해야 한다.


아래처럼 자바스크립트를 생성 후 페이지 호출시 파라메터명으로 fileName에 값을 지정해서 부르면 정확히 파라메터 값을 확인할 수 있다.


<script language="javascript">

    var urlParams = location.search.split(/[?&]/).slice(1).map(function(paramPair) {

        return paramPair.split(/=(.+)?/).slice(0, 2);

    }).reduce(function(obj, pairArray) {

        obj[pairArray[0]] = pairArray[1];

        return obj;

    }, {});

</script>





예를 들어 sample.html이란 페이지에 파라메터는 fileName이라 하고 값은 test를 넘겨보자


sample.html?fileName=test


그리고 자바스크립트에서 urlParams. 하고 파라메터명을 입력하면 확인이 가능하다.


    var fileName = urlParams.fileName;    

    alert(fileName);


이해가 딸리는가?

이해가 딸리는 너님을 위해 이번엔 userName이란 파라메터를 넘겨보자


sample.html?userName=hippalus


그리고 자바스크립트에서 urlParams. 하고 파라메터명을 입력하면 확인이 가능하다.


    var userName = urlParams.userName;    

    alert(userName);


반응형
Posted by Hippalus
,

반응형

super mario run이 예정대로 아이폰 버전으로 출시되었다.
기쁜 마음에 앱스토어로 가보있지만
짝퉁 규퍼마리오만 있고 닌텐도 정발판은 어디에도 없었다.

검색해보니 한국에선 아직 이란다.
http://m.huffpost.com/kr/entry/13001384#cb

뭔소린가 해서 일본 계정으로 일본 앱스토어에 가봤더니



이렇게 버젓이 있었다.

아니 기자양반 이게 무슨 포켓몬 고 도 아니고
뭘 다운을 못받는단 기사를 ㅡㅡ

사람들이 한국 계정만 들고 사는줄 아는가





짜잔~~~



이렇게 한국에서도 슈퍼마리오 런을 즐길 수 있다.

하지만 이미 접한 사람들 평은 좀 안좋다.

수퍼마리오 고고고~

반응형
Posted by Hippalus
,

반응형

<script language="javascript">

var str = "1000000";

// 콤마 찍기

str = str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,');

alert(str);


// 콤마 찍은거 해제시키기

str = str.replace(/[^\d]+/g, '');

alert(str);

</script>

반응형
Posted by Hippalus
,

반응형


<input name="chkName" type="checkbox" id="chkName" value="1" checked <% if isNotUnCheck = True then %>onclick='return false;' <% end if %> />

반응형
Posted by Hippalus
,

반응형

웹개발을 하다보면 동적으로 테이블을 구성해야 하는 상황이 종종 발생한다. colspan은 그나마 쉽지만 rowspan은 쥐약이다. 하지만 jQuery로 간단히 해결 할 수 있어 공유한다.



위 테이블을 아래처럼 합치는 jQuery



구분쎌의 class에 targetCell이라 설정한 후 호출만 해주면 끝남

$(window).load(function () { $(".targetCell").each(function () { var rows = $(".targetCell:contains('" + $(this).text() + "')"); if (rows.length > 1) { rows.eq(0).attr("rowspan", rows.length); rows.not(":eq(0)").remove(); } }); });


반응형
Posted by Hippalus
,