반응형

내 살다살다 이런 경우는 또 처음 경험하게 된다.
보통 xcode에 device를 연결하면 자동으로 애플쪽 device에 등록을 시키고 빌드 / 앱 설치가 가능하다.
그런데 어제부터 특정 시점부터 아래와 같은 오류를 내뱉으며 앱이 실장비 아이폰에 설치가 되지 않기 시작했다.

There is a problem with the request entity: A device with number '00008110-000000000' already exists on this team

Provisioning profile "iOS Team Provisioning Profile: com.mydomain.www doesn't include the currently selected device "iPhone 15" (identifier 00008110-000000000).

developer.apple.com의 devices list에 가봐도 다른 개발 아이폰들은 전부 STATUS가 정상이지만 특정 시점 이후의 아이폰들은 모두 Processing으로 떠있었다.

상단에 친절하게 파란색 영역으로 24시간부터 72시간 정도 걸리네 어쩌네가 있지만 크게 신경은 쓰지 않았다.
왜냐? 10년 넘게 아이폰 개발을 하면서 보통 이런 경우는 프로비저닝 인증서가 문제이거나 기타 애플스러운 오류였기 때문이었다.
더군다나 이번 iOS17이 출시되면서 xcode를 업그레이드 하고나니 pods까지 말썽을 일으켜 12에서 13으로 버전을 업그레이드해야 했으며 이때 pod update가 제대로 먹지 않아 Ruby까지 버전업을 시키는 등 갖은 고초를 겪은 후였다.
느닷없이 firebase쪽 pods에 DT_TOOLCHAIN_DIR 이따위 오류가 나질 않나...

참고로 cocoapods를 12에서 13으로 upgrade시키는 방법은 https://stackoverflow.com/questions/77133579/dt-toolchain-dir-cannot-be-used-to-evaluate-library-search-paths-use-toolchain 를 참고하기 바란다.
물론 위에 적었듯이 Ruby도 업그레이드 해야 하는데 실제 사용하는 system버전도 바꿔줘야 하고 cocoapods를 13으로 upgrade해줘도 이게 version을 확인해보면 여전히 12가 나타나고.. 사람을 애 먹인다.
하지만 기본 방법은 저 방법으로 진행하는게 맞는듯 싶다.
brew upgrade cocoapods
sudo gem install cocoapods
그리고 구글링으로 자주 검색되어 나오는 해결 방법들 중 단골 방법으로 임시방편을 알려주며 Podfile에서 13.0을 12.0으로 바꿔주라는 방법이 검색될텐데 무시해라.
cocoapods가 이미 13버전이 있으므로 삽질해가며 13버전으로 cocoapods를 올리면 그만이다.

  post_install do |installer|
      installer.pods_project.targets.each do |target|
          target.build_configurations.each do |config|
          config.build_settings['IPHONEOS_DEPLOYMENT_TARGET'] = '13.0'
        end
      end
    end



여하튼 앱을 직원들 폰에 테스트를 위해 설치해야 하는데 devices쪽에 등록이 안되고 빌드도 덩달아 해당 폰에 안되고 계속 남의 폰을 붙잡고 있을수도 없는 노릇이라 눈치가 보였지만 여러번 시도하다 어느순간 갑자기 빌드가 되었다.
애플 개발자 사이트에 접속해보니 아니나 다를까 Processing이던 상태값이 모두 사라졌다.

그리고 발견한 내용 -_-
이런 귀여운 애플 녀석들을 보았나.

https://developer.apple.com/help/account/reference/device-registration-updates/

 

Reference - Account - Apple Developer

Reference Device registration updates You need a registered device to create a development or ad hoc provisioning profile. To register a device using your developer account, you need to have the device name and device ID. Temporary processing and ineligibl

developer.apple.com

Temporary processing and ineligible test device status

Enabling registered test devices may require additional processing for new Apple Developer Program memberships or memberships renewed after expiration for one month or more. Although the device is registered during this time, the device identifier won’t be included in provisioning profiles until processing completes. Existing active memberships are not impacted by this change.

Device registration behavior

Registered test device count (per platform)Timeframe*
1 to 10 Upon registration
11 to 100 Within 24 to 72 hours

* Devices may be moved to an ineligible status for up to 30 days if the Provisioning Device Identifier was previously associated to memberships that were terminated for violating the Apple Developer Program License Agreement.

10대까진 바로 디바이스를 등록해주지만 최대치인 100개까진 등록은 해주지만 최소 하루 이상 기다리게 만든다란 내용이다.
이런 내용은 devices list에 링크를 이동시켜주던가 좀 더 자세히 알려주던가.
하여간 양놈들 일처리 방식은 (그나마 구글보단 양반이긴 하다만)

그동안 아이폰 개발을 하며 개발 디바이스를 아무리 많이 사용해도 3대 이상 사용해본적 없었는데 이번 회사에선 10여대를 설치하니 이런 삽질을 하게 되었다.

10대 이상 디바이스를 등록하려면 11대부터는 하루 기다려라.

사족으로 ruby 업그레이드 하는 방법은 이 블로그 참고하기 바람
https://ios-development.tistory.com/1202

 

rbenv를 이용한 ruby 버전 관리 방법 (with gem, bundler)

rbenv ruby 버전 관리를 할 때 사용하는 패키지 rbenv말고도 RVM으로도 ruby를 사용할 수 있지만, RVM이 기능이 많지만 rbenv가 더욱 가벼운 장점이 존재 MacOS를 설치하면 ruby가 내장되어 있지만, ruby 프로

ios-development.tistory.com

% rbenv -v
zsh: command not found: rbenv

% brew install rbenv ruby-build

현재 설치된 ruby 버전 확인
ruby -v

설치하고싶은 ruby 버전 목록 확인
rbenv install -l

원하는 버전 설치
rbenv install 3.0.5

설치한 3.0.5로 글로벌, 로컬 설정
rbenv global 3.0.5
rbenv local 3.0.5

대충 이런식이라는데 버전이야 계속 올라가니 그에 맞게 설치하면 됨.

반응형
Posted by Hippalus
,

반응형

먼저 아이폰 설정 부터 손봐줘야 한다.
설정 앱 > Safari > 고급(맨 아래에 있음) > '웹 속성' OFF를 ON으로 바꿔준다.

다음은 맥에서 Safari앱을 실행한다.
Safari를 못 찾는다면 Finder에서 응용프로그램으로 가보면 Safari가 있다.
Safari 실행 후 설정으로 이동

팝업 윈도우가 뜨면 맨 우측 상단의 고급을 눌러보자
그럼 하단에 메뉴 막대에서 개발자용 메뉴 보기 라는게 체크되어 있는지 확인하고 언체크라면 체크로 바꿔주자 

그럼 Safari의 메뉴들 중 중간 쯤 책갈피와 윈도우 사이에 개발자용이란게 뜨는걸 확인할 수 있을 것이다.

그럼 이제 개발자용을 클릭해보자.

아이폰과 맥이 케이블로 연결되어 있다면 저렇게 연결된 아이폰이 뜰것이고 >를 눌러보면 검사할 수 있는 응용 프로그램 없음 이라고 되어 있을 것이다.

Xcode에서 디버깅 할 wkWebview가 탑재된 앱을 실행하고 다시 Safari를 봐보자
그럼 아깐 검사할 수 있는 응용 프로그램 없음 이라고 되어 있던 곳에 우리의 앱이 보여질 것이다.
거기에 추가로 호출하고 있는 웹페이지까지 보여진다.
만약 테스트 하고 있는 아이폰의 OS가 최신버전인 16.4 버전 이후라면 아래 코드를 webview를 생성하는 곳에 살포시 넣어준다.
        if #available(iOS 16.4, *) {
            webView.isInspectable = true
        } else {
            // Fallback on earlier versions
        }
난 didload에서 wkWebview를 addsub해주고 있기 때문에 didload에 넣어줬다.

앱에서 웹뷰의 링크들을 요리조리 눌러보다 보면 오류가 있는 페이지에선 이렇게 오류들이 뜰 것이다.
마치 크롬의 개발자 도구처럼 말이다.

여러가지 웹 사이트내 오류가 확인되고 있는 모습니다.

난 이번에 골탕 먹은게 뭐였냐면 ATS 때문이었다.
개발서버엔 SSL적용이 잘 되지 않았다.
하지만 실서버엔 SSL이 적용 되었다.
따라서 plist.info에 ATS 예외 도메인 처리를 해두었다.
그런데 사이트는 뜨지만 이상하게 자바스크립트단에서 자꾸 막히는 증상이 발현되었기 때문에 도무지 이해가 안 갔는데
기존 소스들이 jQuery js파일을 다운받지 않고 cdn을 사용하여 실시간으로 받아오고 있었고 이 cdn호출시 http로 불러와졌기 때문에 이런 오류가 나는 구조상의 문제였다.

참고로 화면 캡쳐는 이미 ATS 처리를 한 직후의 캡쳐라 jquery오류는 나타나지 않는 모습니다.


오류가 확인되었으니 마찬가지로 예외 도메인으로 등록해주면 되니 아래처럼 plist.info를 설정해주니 
App Transport Security Settings
Allow Arbitrary Loads NO
Exception Domains
   code.jquery.com
      NSTemporaryExceptionMinimumTLSVersion TLSv1.2
      NSIncludesSubdomains YES
      NSExceptionAllowsInsecureHTTPLoads YES
      NSExceptionRequiresForwardSecrecy NO

참 고생했다.

반응형
Posted by Hippalus
,

반응형

swift로 iOS WEB APP을 만들다보면  웹과 앱 사이 통신이야 javascript로 서로 통신을 하니 별 문제가 없는데
앱 이용자와 일반 모바일 웹 이용자의 화면 UI를 다르게 제공할 일이 존재한다.
가령 GNB에 앱 설정을 불러오는 버튼은 앱 이용자에게만 지원할 때 인데 모바일 웹에선 앱의 기능 설정할 일이 없을테니 말이다.
useragent로 확인을 한들 사파리 브라우저로 접속 하든 앱의 wkwebview로 접속 하든 아주  아니 똑같다.

어쩔 수 없다.
앱으로 접속할 땐 url을 호출할 때 custom agent로 agent를 마사지 해줘야 한다.


webView.evaluateJavaScript("navigator.userAgent") {(result, error) in 
let originUserAgent = result as! String
    let customAgent = originUserAgent + " IOSAPP"
    self.webView.customUserAgent = customAgent 
}

이렇게 보내주고 웹에서 agent를 분석할 때 IOSAPP이 존재하면 아하 우리 회원님이 앱을 사용하고 계시는구나~ 하며 앱용 기능을 제공하면 되겠다.

물론 앱에서 웹쪽으로 "이보시게 관상가 양반. 내가 앱이 될 상인가?" 라며 JAVASCRIPT 함수 하나를 서로 약속하고 호출하면 웹에선 이를 쿠키로 저장하든 세션으로 저장하든 하여 "성군 앱이 되실 분 이십니다."라며 처리해도 무방하나 좀 없어보인다.

반응형
Posted by Hippalus
,

반응형

윈도우 11로 넘어오면서 편리한 기능도 있지만 대표적으로 불편한 기능이 존재한다.
바로 마우스 우클릭 후 나타나는 팝업 컨텍스트 메뉴에서 새폴더 만들기나 바로가기 만들기 같은것들을 이용하려면
추가 옵션 표시를 눌러야만 된다. -_-

윈도우 10까지만 해도 직관적으로 새폴더를 만들 수 있었고 마우스 우측으로 바탕화면으로 바로가기도 수월히 만들 수 있었다.

이런 변화는 상당히 불편하다 못해 불쾌하기 짝이 없다.
이를 해결하기 위해선 레지스트리를 변경해 줘야 한다.
일단 윈도우키 또는 좌측 하단의 윈도우 아이콘을 누른 후 cmd를 입력하고 엔터를 치자.


Windows 10 스타일의 우클릭 메뉴를 사용하고 싶다면 아래 reg.exe부터 /f /ve까지 한줄을 복사해서 붙여넣기 후 엔터를 쌔리자.

reg.exe add "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32" /f /ve

하는김에 짜증나던 탐색기 상단 UI도 Windows 10 스타일로 바꾸자.

reg.exe add "HKCU\Software\Classes\CLSID\{d93ed569-3b3e-4bff-8355-3c44f6a52bb5}\InprocServer32" /f /ve

만약 난 윈도우 11이 좋아~ 라면 아래 명령어로 복원도 가능하다.
Windows 11 스타일의 우클릭 메뉴 복원하기
reg.exe delete "HKCU\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}" /f
 
Windows 11 스타일의 탐색기 상단 UI  복원하기
reg.exe delete "HKCU\Software\Classes\CLSID\{d93ed569-3b3e-4bff-8355-3c44f6a52bb5}" /f
 

반응형
Posted by Hippalus
,

반응형

//먼저 이런 파일명이 존재한다 치자 일부러 .을 파일명에도 넣었다.
var strData = "동해물과. 백두산이.txt"

// 파일명과 확장자를 .으로 분리한다.
if let lastDotIndex = strData.lastIndex(of: ".") {
    let fileNameWithoutExtension = String(strData[strData.startIndex..<lastDotIndex])
    print(fileNameWithoutExtension) // 출력: "동해물과. 백두산이"
} else {
    print("확장자가 없는 파일명입니다.")
}

// 다음은 원하는 자릿수부터 자릿수까지 추출한다.
// 1번째 글자부터 (0이면 처음임) 8번째 자리까지 추출한다.
let startIndex = strData.index(strData.startIndex, offsetBy: 1)
let endIndex = strData.index(strData.startIndex, offsetBy: 3)

let extractedSubstring = strData[startIndex..<endIndex]

print(extractedSubstring) // 해물

반응형
Posted by Hippalus
,

반응형

간단히 사람배열과 그 사람의 보유금액배열을 스위프트로 생성해 보겠다.
사람배열은 문자열형, 보유금액배열은 Int형이다.

var arrPerson:[String] = []
var arrMoney:[Int] = []

// 한명씩 append시키고
arrPerson.append("홍길동")
arrPerson.append("고길동")
arrPerson.append("둘리")

//순서대로 보유금액을 append시킨다.
arrMoney.append(10000000)
arrMoney.append(30000000)
arrMoney.append(0)

//이제 dictionary를 선언한다. key, value는 String,Int형이다. key에는 이름이 value에는 금액이 들어갈 것이다.
var dicData = [String:Int]()

//사람과 보유금액의 배열은 1:1이므로 사람이든 금액이든 아무 배열이나 잡고 돌리면 되지만 난 사람 배열로 돌린다.
for i in 0..<arrPerson.count {
    //dictionary의 key에 사람배열의 값, value에 보유금액의 값을 저장한다.
    dicData[arrPerson[i]] = arrMoney[i]
}

// 출력해보면 순서대로 홍길동 10000000, 고길동 30000000, 둘리 0이 찍히는것을 확인할 수 있다.
for (key, value) in dicData {
    print("\(key) : \(value)")
}

print("정렬 후 결과")

// 이제 정렬을 해보자
// 오름차순정렬이고 만약 내림차순이 하고싶다면 $0.1 < $1.1 대신 $0.1 > $1.1바꿔주면 된다.
// 참고로 0.1, 1.1은 첫번째 인자의 value 두번째 인자의 value를 뜻한다.
// 결과는 튜플로 반환가능하다.
var tupSortResult = dicData.sorted {$0.1 < $1.1}

//print해보면 정렬된 상태로 확인된다.
//[(key: "둘리", value: 0), (key: "홍길동", value: 10000000), (key: "고길동", value: 30000000)]
print("\(tupSortResult)")

//for문을 통해 돌려가며 찍어보면 아래처럼 보여진다.
// 둘리 0
// 홍길동 10000000
// 고길동 30000000
for i in 0..<tupSortResult.count {
    print("\(tupSortResult[i].key) \(tupSortResult[i])")
}

반응형
Posted by Hippalus
,

반응형

visual studio code를 설치하고 나면 기본 언어 설정이 auto인지라 메뉴명이나 결과안내 메세지들이 영어로 나온다.
영어가 익숙한 자들이야 그냥 쓰면 되겠지만 세종대왕의 얼을 지키려드는 자는 한글로 바꿔주면 되겠다.

방법은 쉽다.

참고로 난 chatGPT에 물어보니 한 세번 엉뚱한 답을 줬지만 결국 바른 답을 내주었다.

먼저 좌측 하단의 톱니바퀴 아이콘을 클릭 후 팝업컨텍스트 메뉴에서 설정메뉴를 누르거나 단축키로 ctrl + , 키를 누른다.

그럼 설정 메뉴가 호출되는데

여기 상단의 설정 검색이란 텍스트 박스에 아래와 같이 입력한다.
locale

그럼 맨 위에 TypeScript:Locale이 보이는데 
콤보박스에서 ko를 선택하고 vscode를 종료 후 다시 실행한다.

그럼 이처럼 영어 메뉴나 메세지들이 한글로 보이기 시작한다.

반응형
Posted by Hippalus
,

반응형

1차원 배열은 redim Preserve로 가능하지만
2차원 배열은 redim Preserve 순간 오류를 발생시킨다.
따라서 2차원 배열의 동적 할당을 원할 경우 최대 행 개수로 미리 Row를 할당시키는 수 밖에 없다.
사실상 절반의 동적 할당만 가능하다.

무슨 소리냐면
로직을 진행시키며 for문 등에서 조건에 맞을 때만 2차원 배열을 증가시키고 싶을 때가 있는데 이때 불가능하다란 이야기이다.
좀더 구체적으로 보자면
db에서 select를 해온다 치자
레코드의 수가 100건이다면 2차원 배열을 아래처럼 100개의 row를 보유한 2차원 배열 생성이 가능하다.
ReDim arrData(레코드의카운트-1, 1)
그런데 100건 중 특정 값을 갖고 있는 배열로만 생성하고 싶다하여 아래처럼 불가능하다.
nCount = 0
do until rs.eof
   if rs("isData") = "Y" then
      ReDim Preserve arrSlideImg(nCount , 1)
      nCount = nCount +1
   end if
   rs.movenext
loop

따라서 굳이 동적 할당이 필요하다면 일단 레코드의 수만큼만 배열을 생성하고
배열을 돌며 실제 출력할 때 빈 배열이면 exit for등으로 탈출하는 수 밖에 없다.

아래는 일반적인 2차원 배열의 동적 할당 코드 샘플이다.

<%
Dim arrData() ' 2차원 배열 선언
Dim numRows ' 행(row)의 개수를 저장할 변수

' 행(row)의 개수를 가변적으로 지정
Dim maxRows ' 최대 행(row) 개수
maxRows = 10 ' 예제에서는 최대 10으로 지정

' 변수의 값을 조건에 따라 증가시키며 배열 크기 동적 할당
numRows = 0 ' 초기 행(row) 개수는 0
ReDim arrData(maxRows - 1, 1) ' 배열 크기 동적 할당
Do While numRows < maxRows
    numRows = numRows + 1 ' 행(row) 개수 증가

    ' 배열에 데이터 채우기
    arrData(numRows - 1, 0) = numRows ' 첫 번째 열(column)에는 행(row) 번호 저장
    arrData(numRows - 1, 1) = "Data " & numRows ' 두 번째 열(column)에는 데이터 저장
Loop

' 배열 데이터 출력
Response.Write("<table border='1'>")
For i = 0 To numRows - 1
    Response.Write("<tr>")
    For j = 0 To 1
        Response.Write("<td>" & arrData(i, j) & "</td>")
    Next
    Response.Write("</tr>")
Next
Response.Write("</table>")
%>

반응형
Posted by Hippalus
,

반응형

 -- MSSQL 전체컬럼 확인방법
SELECT
   TBLNAME.name AS TBLNAME, COLNAME.name AS COLNAME
FROM
   sys.tables AS TBLNAME
   INNER JOIN sys.columns AS COLNAME ON TBLNAME.object_id = COLNAME.object_id


-- MSSQL 특정컬럼 검색방법
SELECT
   TBLNAME.name AS table_name, COLNAME.name AS column_name
FROM
   sys.tables AS TBLNAME
   INNER JOIN sys.columns AS COLNAME ON TBLNAME.object_id = COLNAME.object_id
WHERE
COLNAME.name = '찾으려는 컬럼명'

반응형
Posted by Hippalus
,

반응형

보통 게시판 페이징 쿼리를 만들 때 두가지 방법을 쓴다.
구닥다리 방법은 먼저 불러올 전체 카운트를 구하고 이를 토대로 실제 불러오는 쿼리에서 NOT IN으로 제외하고 불러오는 쿼리인데
똑같은 쿼리를 남발해야 하므로 아직도 사용하는 곳이 있다면 문제가 심각해 보이므로 PASS

두번째 방법은 ROW_NUMBER를 이용하는 쿼리인데 ROW_NUMBER()로 내마음속 번호를 생성시킨 후 이를 기준으로 페이징을 한다.
그나마 써줄만하다.

SELECT
   MEMTBL.USERID_IDX
FROM (
   SELECT ROW_NUMBER() OVER (ORDER BY USERID_IDX) AS ROWNUM, USERID_IDX FROM MEMBER_TABLE 
       ) AS MEMTBL
WHERE
   MEMTBL.ROWNUM BETWEEN 1 AND 10
 
마지막으로 MS-SQL 2012 이후 부터 사용가능한 쿼리인데 아래처럼 간결한 쿼리가 가능해졌다.

SELECT
   USERID_IDX
FROM
   MEMBER_TABLE WITH (NOLOCK)
ORDER BY 
   USERID_IDX
OFFSET 0 ROWS FETCH NEXT 10 ROWS ONLY

시작위치는 OFFSET으로 지정하고
FETCH NEXT로 몇번까지 불러올지 지정만 하면 그만이다.

반응형
Posted by Hippalus
,