반응형

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

앱에서 앱으로 호출

Info.plist 설정 후 OpenURL함수를 통해 호출한다.

 

Info.plist 설정

  • 호출하는 쪽 URL Scheme 설정 (샘플앱 명 : sendApp)

 

  • 호출받는 쪽 URL Scheme 설정 (샘플앱 명 : receiveApp)

 

※ Xcode 11부터 SceneDelegate가 기본 iOS 앱 프로젝트 템플릿으로 자동으로 추가되면서 AppDelegate의 openURL 함수가 호출 되지 않으므로 SceneDelegate의 openURLContexts 함수에서 처리해야 한다.

// SceneDelegate.swift
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>) {
    if let url = URLContexts.first?.url {
        print("url = \(url)")
    }
}
// SceneDelegate.m
- (void)scene:(UIScene *)scene openURLContexts:(NSSet *)URLContexts {
    UIOpenURLContext *context = URLContexts.anyObject;
    NSURL *url = context.URL;
    NSLog(@"url = %@",url);
}
// Swift 앱 호출 샘플코드
if UIApplication.shared.canOpenURL(url) {
    if #available(iOS 10.0, *) {
        UIApplication.shared.open(url, options: [:], completionHandler: { (success) in

        })
    } else {
        UIApplication.shared.openURL(url)
    }
}
        
// Objective-C 앱 호출 샘플코드
if (YES == [[UIApplication sharedApplication] canOpenURL:url]) {
    if (@available(iOS 10.0, *)) {
        [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:^(BOOL success) {}];
    } else {
        [[UIApplication sharedApplication] openURL:url];
    }
    return;
}

 

 

모바일 웹에서 앱 호출

  • 웹 브라우저(사파리,크롬 등)을 통한 웹사이트에서 앱 호출
window.location = "receiveApp://";

 

  • 웹뷰(WKWebView)를 통한 웹사이트에서 앱 호출

      ※ 주의 : 이 경우 해당 URL scheme이 호출될 때 직접 코드로 호출 해 주어야 한다. 

func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) {
    guard let url = navigationAction.request.url else {
        decisionHandler(.cancel)
        return
    }
    
    if (url.absoluteString.hasPrefix("receiveApp://")) {
        if UIApplication.shared.canOpenURL(url) {
            if #available(iOS 10.0, *) {
                UIApplication.shared.open(url, options: [:], completionHandler: { (success) in
                    
                })
            } else {
                UIApplication.shared.openURL(url)
            }
        }
        decisionHandler(.cancel)
        return
    }
    
    ... 중간생략 ...
}

 

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

2021/01/06 - [iOS/Swift] - String to CGFloat

2021/01/05 - [iOS/Tips] - SceneDelegate 포인터 구하기

2021/01/05 - [iOS/Tips] - 앱 호출 (URL scheme)

2020/12/24 - [개발노트] - 라이선스 종류

2020/12/24 - [OS/Mac OS X] - MacBook을 AP로 설정하는 방법

2020/12/18 - [Arduino] - Bit Rate, Baud Rate

2020/12/18 - [Arduino] - RS232 Serial 통신 불량체크

2020/12/17 - [프로그래밍/Java] - Java HotSpot(TM) 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

2020/12/17 - [OS/Mac OS X] - OpenSSL을 이용한 Key 정보 Text 변환

2020/12/17 - [프로그래밍/Java] - RSA 암복호화

2020/12/17 - [iOS/Tips] - URL query 파싱 및 json string 변환

2020/12/16 - [개발노트] - Code 128 Barcode의 Check Digit 계산방법

2020/12/15 - [iOS/Tips] - 디버깅 차단 처리 (Anti Debug)

2020/12/14 - [iOS/Tips] - bundle id 알아내기

2020/12/12 - [AI/Algorithm] - 2D 충돌처리

반응형

'개발 > iOS' 카테고리의 다른 글

String to CGFloat  (0) 2021.01.06
SceneDelegate 포인터 구하기  (0) 2021.01.05
URL query 파싱 및 json string 변환  (0) 2020.12.17
디버깅 차단 처리 (Anti Debug)  (0) 2020.12.15
bundle id 알아내기  (0) 2020.12.14
블로그 이미지

SKY STORY

,
반응형
// 사용 방법
let url = URL(string:"https://www.test.com/myconmand?param1=ASDF&param2=1234")!
let qParams = url.queryParams().toJsonString()
let param2 = url.valueOf("param2")

print(
    """
    scheme      = \(url.scheme ?? "")
    host        = \(url.host ?? "")
    path        = \(url.path)
    query       = \(url.query ?? "")
    qParams     = \(qParams)
    param2      = \(param2 ?? "")
    """
)

// 결과 
scheme      = https
host        = www.test.com
path        = /myconmand
query       = param1=ASDF&param2=1234
qParams     = {"param1":"ASDF","param2":"1234"}
param2      = 1234
extension URL {
    
    func queryParams() -> [String:Any] {
        let queryItems = URLComponents(url: self, resolvingAgainstBaseURL: false)?.queryItems
        let queryTuples: [(String, Any)] = queryItems?.compactMap{
            guard let value = $0.value else { return nil }
            return ($0.name, value)
        } ?? []
        return Dictionary(uniqueKeysWithValues: queryTuples)
    }
    
    func valueOf(_ queryParamaterName: String) -> String? {
        guard let url = URLComponents(string: self.absoluteString) else { return nil }
        return url.queryItems?.first(where: { $0.name == queryParamaterName })?.value
    }
    
}
extension Dictionary {

    func toJsonData() -> Data {
        var jsonData: Data?
        do {
            jsonData = try JSONSerialization.data(withJSONObject: self, options: .init(rawValue: 0))
        } catch {
            print(error)
        }
        return jsonData!
    }

    func toJsonDataPrettyPrinted() -> Data {
        var jsonData: Data?
        do {
            jsonData = try JSONSerialization.data(withJSONObject: self, options: JSONSerialization.WritingOptions.prettyPrinted)
        } catch {
            print(error)
        }
        return jsonData!
    }
    
    func toJsonString() -> String {
        return toJsonData().toString()
    }
    
    func toPrettyPrintedJsonString() -> String {
        return toJsonDataPrettyPrinted().toString()
    }
    
}
extension Data {
    func hexString() -> String {
        return map { String(format: "%02hhx", $0) }.joined()
    }
    
    func toString() -> String {
        return String(data: self, encoding: String.Encoding.utf8)!
    }
}

 

2020/12/16 - [개발노트] - Code 128 Barcode의 Check Digit 계산방법

2020/12/15 - [iOS/Tips] - 디버깅 차단 처리 (Anti Debug)

2020/12/14 - [iOS/Tips] - bundle id 알아내기

2020/12/12 - [AI/Algorithm] - 2D 충돌처리

2020/12/11 - [iOS/Swift] - UIViewController 스위칭

2020/12/11 - [개발노트] - PlantUML 설치 (Mac OS X)

2020/12/11 - [개발노트] - 특수문자 발음

2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법 

반응형

'개발 > iOS' 카테고리의 다른 글

SceneDelegate 포인터 구하기  (0) 2021.01.05
앱 호출 (URL scheme)  (0) 2021.01.05
디버깅 차단 처리 (Anti Debug)  (0) 2020.12.15
bundle id 알아내기  (0) 2020.12.14
UIViewController 스위칭  (0) 2020.12.11
블로그 이미지

SKY STORY

,
반응형

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

앱 실행 시 디버깅 정보 접근 차단 처리

아래 클래스는 Objective-C, C 언어로 작성되었고

Swift 프로젝트에 사용되었습니다.

Release 빌드시에만 적용되도록 처리하였습니다. 

//
//  AntiDebug.h
//
//  Created by netcanis on 2020/05/22.
//  Copyright © 2020 netcanis. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface AntiDebug : NSObject

+ (BOOL)run;

@end

NS_ASSUME_NONNULL_END

 

//
//  AntiDebug.m
//
//  Created by netcanis on 2020/05/22.
//  Copyright © 2020 netcanis. All rights reserved.
//

#import "AntiDebug.h"
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>


////////////////////////////////////////////////////////////////////////
// 배포시 자동으로 안티디버깅 활성화 - 0:디버깅 연결, 1:디버깅 차단
#ifdef DEBUG
#define ANTI_DEBUG      (0) // 개발시 - 디버깅
#else
#define ANTI_DEBUG      (1) // 배포시 - 디버깅 차단
#endif//DEBUG
////////////////////////////////////////////////////////////////////////


//
// Anti Debug 처리
//

#if ANTI_DEBUG

// For debugger_ptrace.
// Ref: https://www.theiphonewiki.com/wiki/Bugging_Debuggers
#import <dlfcn.h>
#import <sys/types.h>

// For debugger_sysctl
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/sysctl.h>
#include <stdlib.h>

// For ioctl
#include <termios.h>
#include <sys/ioctl.h>

// For task_get_exception_ports
#include <mach/task.h>
#include <mach/mach_init.h>

// For kdebug_signpost
#import <sys/kdebug_signpost.h>

typedef int (*ptrace_ptr_t)(int _request, pid_t _pid, caddr_t _addr, int _data);

#if !defined(PT_DENY_ATTACH)
#define PT_DENY_ATTACH 31
#endif  // !defined(PT_DENY_ATTACH)

/*!
 @brief This is the basic ptrace functionality.
 @link http://www.coredump.gr/articles/ios-anti-debugging-protections-part-1/
 */
void debugger_ptrace()
{
    void* handle = dlopen(0, RTLD_GLOBAL | RTLD_NOW);
    ptrace_ptr_t ptrace_ptr = dlsym(handle, "ptrace");
    ptrace_ptr(PT_DENY_ATTACH, 0, 0, 0);
    dlclose(handle);
}

/*!
 @brief This function uses sysctl to check for attached debuggers.
 @link https://developer.apple.com/library/mac/qa/qa1361/_index.html
 @link http://www.coredump.gr/articles/ios-anti-debugging-protections-part-2/
 */
static bool debugger_sysctl(void)
// Returns true if the current process is being debugged (either
// running under the debugger or has a debugger attached post facto).
{
    int mib[4];
    struct kinfo_proc info;
    size_t info_size = sizeof(info);
    
    // Initialize the flags so that, if sysctl fails for some bizarre
    // reason, we get a predictable result.
    
    info.kp_proc.p_flag = 0;
    
    // Initialize mib, which tells sysctl the info we want, in this case
    // we're looking for information about a specific process ID.
    
    mib[0] = CTL_KERN;
    mib[1] = KERN_PROC;
    mib[2] = KERN_PROC_PID;
    mib[3] = getpid();
    
    // Call sysctl.
    
    if (sysctl(mib, 4, &info, &info_size, NULL, 0) == -1)
    {
        perror("perror sysctl");
        exit(-1);
    }
    
    // We're being debugged if the P_TRACED flag is set.
    
    return ((info.kp_proc.p_flag & P_TRACED) != 0);
}

static bool antiDebug(void)
{
//    // Determine if iOS device is 32- or 64-bit
//    if (sizeof(void*) == 4) {
//        NSLog(@"32-bit App");
//    } else if (sizeof(void*) == 8) {
//        NSLog(@"64-bit App");
//    }
    
    
    // If enabled the program should exit with code 055 in GDB
    // Program exited with code 055.
    debugger_ptrace();
    NSLog(@"Bypassed ptrace()");
    
    // If enabled the program should exit with code 0377 in GDB
    // Program exited with code 0377.
    if (debugger_sysctl())
    {
        //return -1;
        return NO;
    } else {
        NSLog(@"Bypassed sysctl()");
    }
    
    // Another way of calling ptrace.
    // Ref: https://www.theiphonewiki.com/wiki/Kernel_Syscalls
    #if __IPHONE_OS_VERSION_MIN_REQUIRED < __IPHONE_10_0
    // 'syscall' is deprecated: first deprecated in iOS 10.0 - syscall(2) is unsupported;
    // please switch to a supported interface.
    // For SYS_kdebug_trace use kdebug_signpost().
    syscall(26, 31, 0, 0);
    NSLog(@"Bypassed syscall()");
    #endif
    
    // Ref: https://reverse.put.as/wp-content/uploads/2012/07/Secuinside-2012-Presentation.pdf
    struct ios_execp_info
    {
        exception_mask_t masks[EXC_TYPES_COUNT];
        mach_port_t ports[EXC_TYPES_COUNT];
        exception_behavior_t behaviors[EXC_TYPES_COUNT];
        thread_state_flavor_t flavors[EXC_TYPES_COUNT];
        mach_msg_type_number_t count;
    };
    struct ios_execp_info *info = malloc(sizeof(struct ios_execp_info));
    kern_return_t kr = task_get_exception_ports(mach_task_self(), EXC_MASK_ALL, info->masks, &info->count, info->ports, info->behaviors, info->flavors);
    NSLog(@"Routine task_get_exception_ports : %d", kr);
    
    for (int i = 0; i < info->count; i++)
    {
        if (info->ports[i] !=0 || info->flavors[i] == THREAD_STATE_NONE)
        {
            NSLog(@"Being debugged... task_get_exception_ports");
        } else {
            NSLog(@"task_get_exception_ports bypassed");
        }
    }
    
    // Another way of figuring out if LLDB is attached.
    if (isatty(1)) {
        NSLog(@"Being Debugged isatty");
    } else {
        NSLog(@"isatty() bypassed");
    }
    
    // Yet another way of figuring out if LLDB is attached.
    if (!ioctl(1, TIOCGWINSZ)) {
        NSLog(@"Being Debugged ioctl");
    } else {
        NSLog(@"ioctl bypassed");
    }
    
    // Everything above relies on libraries. It is easy enough to hook these libraries and return the required
    // result to bypass those checks. So here it is implemented in ARM assembly. Not very fun to bypass these.
#ifdef __arm__
    asm volatile (
                  "mov r0, #31\n"
                  "mov r1, #0\n"
                  "mov r2, #0\n"
                  "mov r12, #26\n"
                  "svc #80\n"
                  );
    NSLog(@"Bypassed syscall() ASM");
#endif
#ifdef __arm64__
    asm volatile (
                  "mov x0, #26\n"
                  "mov x1, #31\n"
                  "mov x2, #0\n"
                  "mov x3, #0\n"
                  "mov x16, #0\n"
                  "svc #128\n"
                  );
    NSLog(@"Bypassed syscall() ASM64");
#endif
    
    return YES;
}
#endif//ANTI_DEBUG


@implementation AntiDebug

+ (BOOL)run {
#if ANTI_DEBUG
    return antiDebug();
#endif
    return YES;
}

@end

 

//
//  XXX-Bridging-Header.h
//
//  Created by netcanis on 2019/11/25.
//  Copyright © 2019 netcanis. All rights reserved.
//

#ifndef XXX_Bridging_Header_h
#define XXX_Bridging_Header_h

#import "AntiDebug.h"

#endif /* XXX_Bridging_Header_h */

 

//
//  AppDelegate.swift
//
//  Created by netcanis on 2019/11/25.
//  Copyright © 2019 netcanis. All rights reserved.
//

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        guard AntiDebug.run() else {
            return false
        }
        
		... 생략 ...
    
        return true
    }

 

스마트폰 BTC 채굴앱

https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site

 

2020/12/14 - [iOS/Tips] - bundle id 알아내기

2020/12/12 - [AI/Algorithm] - 2D 충돌처리

2020/12/11 - [iOS/Swift] - UIViewController 스위칭

2020/12/11 - [개발노트] - PlantUML 설치 (Mac OS X)

2020/12/11 - [개발노트] - 특수문자 발음

2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

2020/12/08 - [프로그래밍/Java Script] - Android, iOS 앱 설치여부 체크 및 스토어 이동

2020/08/21 - [Android/Tips] - aab파일 apk파일로 변환

2020/08/11 - [iOS/Swift] - WKWebView 화면 출력 완료 이벤트

2020/08/06 - [iOS/Tips] - 개발관련 폴더 경로

2020/07/19 - [Android/Tips] - 안드로이드 원격 디버깅 방법

반응형

'개발 > iOS' 카테고리의 다른 글

앱 호출 (URL scheme)  (0) 2021.01.05
URL query 파싱 및 json string 변환  (0) 2020.12.17
bundle id 알아내기  (0) 2020.12.14
UIViewController 스위칭  (0) 2020.12.11
웹뷰에서 javascript 함수 동기식 호출  (0) 2020.12.10
블로그 이미지

SKY STORY

,

bundle id 알아내기

개발/iOS 2020. 12. 14. 15:15
반응형

스마트폰 BTC 채굴앱
https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site


iOS기기에 설치된 앱의 bundle id를 알아내는 방법을 알아보자.
직접 개발중이라면 당연히 알 수 있지만 앱스토어에서 설치한 앱의 번들아이디를 얻으려면 어떻게 할까.
물론 탈옥되지 않은 폰으로 말이다.

ipa 파일의 번들아이디를 구할 경우 :

- ipa확장자를 zip으로 변경한 뒤 압축을 푼다.
- 디렉토리 내에 XXX.app파일을 선택하고 우클릭하여 'Show Package Contents' 선택

- 폴더 내 'Info.plist'파일을 열어 원하는 정보를 취득한다.
- bundle id에 대한 키는 'CFBundleURLName'이다.

앱스토어에서 설치한 앱의 경우 :

- Console.app 실행

- 기기를 연결하고 앱을 실행한다.
- 좌측 Devices 목록에서 디바이스 선택
- 우측 상단 검색으로 '(bundle)'라고 입력

- 설치된 앱들의 bundle id중 찾고자 한 앱을 찾는다.


스마트폰 BTC 채굴앱
https://get.cryptobrowser.site/34473645

 

Earn coins while browsing the web

Earn bitcoins while watching videos, chatting, or playing online. It has never been so easy to increase your income! Tell your friends about CryptoTab Browser, invite them to join, and earn more together. Grow your network—get more profit!

get.cryptobrowser.site


2020/12/12 - [AI/Algorithm] - 2D 충돌처리
2020/12/11 - [iOS/Swift] - UIViewController 스위칭
2020/12/11 - [개발노트] - PlantUML 설치 (Mac OS X)
2020/12/11 - [개발노트] - 특수문자 발음
2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출
2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)
2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)
2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

반응형

'개발 > iOS' 카테고리의 다른 글

URL query 파싱 및 json string 변환  (0) 2020.12.17
디버깅 차단 처리 (Anti Debug)  (0) 2020.12.15
UIViewController 스위칭  (0) 2020.12.11
웹뷰에서 javascript 함수 동기식 호출  (0) 2020.12.10
Fat Static Library 빌드 (2/2)  (0) 2020.12.10
블로그 이미지

SKY STORY

,
반응형

손쉬운 업데이트를 위해 대부분의 회사에서 하이브리드 앱으로 개발을 합니다.

이 과정에 특정 서비스의 경우 웹뷰를 따로 구성해야하는 상황이 발생합니다.

예를들어, AViewController, BViewController와 같이 UIViewController를 상속받는 ViewController를 따로 생성하여 웹뷰를 구성하게 됩니다. 이러한 구성에 따로 생성된 뷰컨트럴러간 스위칭이 필요한 경우가 발생합니다.

+ UINavigationController

   - AViewController

   - BViewController

   - CViewController

위와 같은 경우 마지막에 추가된 CViewController가 화면에 출력됩니다.

UINavigationController의 뷰컨트럴러 배열의 순서를 변경하면 원하는 뷰컨트럴러를 최상단으로 올릴 수 있습니다.

다음은 해당 기능을 구현한 클래스입니다.

extension UINavigationController {
	// 주어진 UIViewController를 제거합니다.
    func removeVC(_ kindClass: AnyClass) {
        self.viewControllers = self.viewControllers.filter {!$0.isKind(of:kindClass)}
    }
    
    // 주어진 UIViewController가 존재하는지 체크
    func containsVC(_ kindClass: AnyClass) -> Bool {
        return self.viewControllers.contains(where: {$0.isKind(of:kindClass)})
    }
    
    // 주어진 UIViewController를 최상위에 출력되도록 합니다.
    func setTopVC(_ kindClass: AnyClass) -> UIViewController? {
        var stack: [UIViewController] = self.viewControllers
        var index: Int = 0
        for vc in stack {
            if vc.isKind(of: kindClass) {
                stack.remove(at: index)
                stack.append(vc)
                self.viewControllers = stack
                return vc
            }
            index += 1
        }
        return nil
    }
    
    // 주어진 UIViewController를 존재하는 경우 최상위에 출력되도록 합니다.
    func activateVC(_ kindClass: AnyClass) {
        if containsVC(kindClass) {
            _ = setTopVC(kindClass)
        }
    }
}

extension UIViewController {
	// 옵져버 추가
    func addObserver(_ aSelector: Selector) {
        NotificationCenter.default.addObserver(self,
                                               selector: aSelector,
                                               name: NSNotification.Name(self.theClassName),
                                               object: nil)
    }
	
    // 옵져버 삭제
    func removeObserver() {
        NotificationCenter.default.removeObserver(self)
    }
    
    // 타깃 뷰컨트럴러로 데이터 전달 
    func post(_ targetClassName: String, _ userInfo: [AnyHashable : Any], _ delay: Double = 0.0) {
        let delayTime: Double = (delay < 0) ? 1.0 : delay
        Timer.scheduledTimer(withTimeInterval: delayTime, repeats: false, block: {_ in
            NotificationCenter.default.post(name: NSNotification.Name(targetClassName),
            object: nil,
            userInfo: userInfo)
        })
    }
}



//
// BViewController
// 

override func viewDidLoad() {
    super.viewDidLoad()
    addObserver(#selector(onCommand))
    ... 중간 생략 ...
}
        
deinit {
    removeObserver()
}

... 중간 생략 ...

@objc func onCommand(notification: Notification) {
    guard notification.name.rawValue == self.theClassName else { return }
    guard let userInfo = notification.userInfo else { return }
    
    let name = userInfo["name"] as? String ?? ""
    if name == "이벤트이름" {
        let paramString = userInfo["data"] as! String
        self.sendScript(name: "이벤트이름", result: paramString)
    }
    else {
        //self.userMethod = name
        //self.userInfo = userInfo["data"] as! Dictionary <String, Any>
    }
}

    

//
// 사용 방법
// : 아래 내용은 CViewController에서 BViewController로 이벤트 데이터를 전달 및 화면 스위칭한다.
//

// BViewController에 이벤트 데이터 정보 전달
post("BViewController", ["name" : "이벤트이름", "data" : "전달할 데이터 정보"])

// 0.5초 딜레이 주어 웹뷰 로딩 시간을 주었다.
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
	self.navigationController?.activateVC(BViewController.self)
}

 

2020/12/11 - [iOS/Swift] - UIViewController 스위칭

2020/12/11 - [개발노트] - PlantUML 설치 (Mac OS X)

2020/12/11 - [분류 전체보기] - Tones And I - Dance Monkey

2020/12/11 - [lyrics] - Beyonce - Halo

2020/12/11 - [개발노트] - 특수문자 발음

2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

2020/12/08 - [프로그래밍/Java Script] - Android, iOS 앱 설치여부 체크 및 스토어 이동

2020/08/21 - [Android/Tips] - aab파일 apk파일로 변환

반응형

'개발 > iOS' 카테고리의 다른 글

디버깅 차단 처리 (Anti Debug)  (0) 2020.12.15
bundle id 알아내기  (0) 2020.12.14
웹뷰에서 javascript 함수 동기식 호출  (0) 2020.12.10
Fat Static Library 빌드 (2/2)  (0) 2020.12.10
Fat Static Library 빌드 (1/2)  (1) 2020.12.10
블로그 이미지

SKY STORY

,
반응형

UIWebview에서 WKWebview로 변경하면서 js함수 호출시 비동기식으로 호출되는 것을 알 수 있다.

그런데 이전 웹 코드가 동기식으로 해야 동작하는 경우가 생길 수 있다.

이 경우 아래와 같이 동기식으로 호출되도록 처리할 수 있다.

@interface WKWebView(SynchronousEvaluateJavaScript)
- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script;
@end

@implementation WKWebView(SynchronousEvaluateJavaScript)

- (NSString *)stringByEvaluatingJavaScriptFromString:(NSString *)script
{
    __block NSString *resultString = nil;
    __block BOOL finished = NO;

    [self evaluateJavaScript:script completionHandler:^(id result, NSError *error) {
        if (error == nil) {
            if (result != nil) {
                resultString = [NSString stringWithFormat:@"%@", result];
            }
        } else {
            NSLog(@"evaluateJavaScript error : %@", error.localizedDescription);
        }
        finished = YES;
    }];

    while (!finished)
    {
        [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
    }

    return resultString;
}
@end

/*
[ 사용 방법 ]
NSString *msg = @"test message";
NSString *param = [NSString stringWithFormat:@"alert('%@')", msg];
[self.webView stringByEvaluatingJavaScriptFromString:param];
*/

 

2020/12/10 - [iOS/Objective-C] - 웹뷰에서 javascript 함수 동기식 호출

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

2020/12/08 - [프로그래밍/Java Script] - Android, iOS 앱 설치여부 체크 및 스토어 이동

2020/08/21 - [Android/Tips] - aab파일 apk파일로 변환

2020/08/11 - [iOS/Swift] - WKWebView 화면 출력 완료 이벤트

2020/08/06 - [iOS/Tips] - 개발관련 폴더 경로

2020/07/19 - [Android/Tips] - 안드로이드 원격 디버깅 방법

2020/07/18 - [Android/Tips] - Cannot convert string value 'JETPACK_COMPOSE' to an enum value of type 'com.android.builder.model.AndroidGradlePluginProjectFlags$BooleanFlag' (valid case insensitive values: APPLICATION_R_CLASS_CONSTANT_IDS, TEST_R_CLASS_CONSTANT_IDS, TRANSITIVE_R_CLASS)

2020/07/18 - [Android/Tips] - OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

반응형

'개발 > iOS' 카테고리의 다른 글

bundle id 알아내기  (0) 2020.12.14
UIViewController 스위칭  (0) 2020.12.11
Fat Static Library 빌드 (2/2)  (0) 2020.12.10
Fat Static Library 빌드 (1/2)  (1) 2020.12.10
Custom UserAgent 설정  (0) 2020.12.10
블로그 이미지

SKY STORY

,
반응형

이번에는 Fat Static Library만드는 작업을 스크립트로 처리하여 자동화 처리하는 방법입니다.

 

Fat Static Library(이하 Fat 라이브러리) 빌드 자동화  스크립트 사용 방법

1. Xcode의 Build Phases에서 스크립트 추가

2. 아래 스크립트 내용을 붙여넣기 한다.

##############################################

#

# Fat static library

#

# Automatically create cross-platform (simulator + device) 

# static libraries for Objective C / iPhone / iPad.

#

# added by netcanis 2018.10.26 

#############################################

set -e

set -o pipefail



# Get BaseSdk version

SDK_VERSION=$(echo ${SDK_NAME} | grep -o '\d\{1,2\}\.\d\{1,2\}$')



# Get build type (Device or Simulator).

if [ ${PLATFORM_NAME} = "iphonesimulator" ]

then

OTHER_SDK_TO_BUILD=iphoneos${SDK_VERSION}

else

OTHER_SDK_TO_BUILD=iphonesimulator${SDK_VERSION}

fi



if [ "true" == ${ALREADYINVOKED:-false} ]

then

echo "RECURSION"

exit 0;

fi





# Building

export ALREADYINVOKED="true"



xcodebuild -configuration "${CONFIGURATION}" -project "${PROJECT_NAME}.xcodeproj" -target "${TARGET_NAME}" -sdk "${OTHER_SDK_TO_BUILD}" ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO BUILD_DIR="${BUILD_DIR}" BUILD_ROOT="${BUILD_ROOT}" SYMROOT="${SYMROOT}"



ACTION="build"



CURRENTCONFIG_DEVICE_DIR=${SYMROOT}/${CONFIGURATION}-iphoneos

CURRENTCONFIG_SIMULATOR_DIR=${SYMROOT}/${CONFIGURATION}-iphonesimulator

CREATING_UNIVERSAL_DIR=${SYMROOT}/${CONFIGURATION}-universal



# Remove previous build floder.

rm -rf "${CREATING_UNIVERSAL_DIR}"

mkdir "${CREATING_UNIVERSAL_DIR}"



# Make universal static library.

xcrun -sdk iphoneos lipo -create -output "${CREATING_UNIVERSAL_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_DEVICE_DIR}/${EXECUTABLE_NAME}" "${CURRENTCONFIG_SIMULATOR_DIR}/${EXECUTABLE_NAME}"



echo "Build complete!"

 

3. 빌드 설정을 ‘Release’로 설정한 후 빌드.

 

4. 빌드시 스크립트를 통해 디바이스와 시뮬레이터 빌드를 하며 ‘Release-universal’폴더에
두 빌드에 대한 Fat 라이브러리를 생성하여 준다.

5. ‘Release-universal’ 폴더에 생성된 Fat라이브러리 ‘libXXX.a’를 배포한다.

 

주의 : 빌드시 적용이 안될 경우 시뮬레이터 빌드를 한번 실행한 뒤 다시 시도해 봅니다.

 

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

2020/12/08 - [프로그래밍/Java Script] - Android, iOS 앱 설치여부 체크 및 스토어 이동

2020/08/21 - [Android/Tips] - aab파일 apk파일로 변환

2020/08/11 - [iOS/Swift] - WKWebView 화면 출력 완료 이벤트

2020/08/06 - [iOS/Tips] - 개발관련 폴더 경로

2020/07/19 - [Android/Tips] - 안드로이드 원격 디버깅 방법

2020/07/18 - [Android/Tips] - Cannot convert string value 'JETPACK_COMPOSE' to an enum value of type 'com.android.builder.model.AndroidGradlePluginProjectFlags$BooleanFlag' (valid case insensitive values: APPLICATION_R_CLASS_CONSTANT_IDS, TEST_R_CLASS_CONSTANT_IDS, TRANSITIVE_R_CLASS)

2020/07/18 - [Android/Tips] - OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

2020/07/17 - [iOS/Tips] - 웹에서 iOS 앱 설치여부 체크

반응형

'개발 > iOS' 카테고리의 다른 글

UIViewController 스위칭  (0) 2020.12.11
웹뷰에서 javascript 함수 동기식 호출  (0) 2020.12.10
Fat Static Library 빌드 (1/2)  (1) 2020.12.10
Custom UserAgent 설정  (0) 2020.12.10
CocoaPods 설치 및 제거  (0) 2020.12.10
블로그 이미지

SKY STORY

,
반응형

정적라이브러리 생성후 배포 시 시뮬레이터로 작업하는 프로젝트의 경우 라이브러리에 해당 아키텍쳐가 포함되어있지 않아 실행할 수 없는 상황이 발생하곤 합니다. 이럴경우 생성된 정적라이브러리에 해당 아키텍처를 포함시켜줄 수 있습니다.

아래의 과정은 배포하는 정적라이브러리를 사용하는 프로젝트에서 시뮬레이터 빌드가 가능하도록 Fat Static Library를 생성하는 방법입니다.

Fat Static Library(이하 Fat 라이브러리) 생성 순서

1. Device 용 빌드
빌드 패스에 ’Release-iphoneos’ 폴더에  저장 됨.

2. Simulator 용 빌드
빌드 패스에 ’Release-iphonesimulator’ 폴더에 저장 됨.

3. Xcode 메뉴에서 Project Seettings… 창을 열면 아래와 같이 빌드 디렉토리 경로를 볼 수 있다.

 

4. 또는 Xcode 의 Project Navigator 에서 Products에 빌드된 파일로 빌드된 디렉토리를 확인할 수 있다.

5. 위 4번 파일을 이용하여 빌드된 디렉토리로 이동하면 다음과 같다.

6. 빌드된 라이브러리 파일을 Device, Simulator에 따라 파일이름을 각각 ‘libXXXD.a’, ‘libXXXS.a’로 바꿔 Desktop에 복사한다.

7. 콘솔창을 띄워 Desktop폴더로 이동

cd ~/Desktop

8. 콘솔창에서 lipo명령을 통해 Device와 Simulator 로 빌드된 두 라이브러리를 합친다. 

lipo -create ./libXXXD.a ./libXXXS.a -output ./libXXX.a

9. 8번에서 생성된 Fat 라이브러리 Architectures 를 확인 하도록 한다.
lipo -I libXXX.a

10. 9 결과가 Device 아키텍쳐(armv7, arm64, armv7s) Simulator 아키텍쳐(i386, x86_64)
포함되었다면 정상이므로 ‘libXXX.a’ 배포하도록 한다.

 

 

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (2/2)

2020/12/10 - [iOS/Tips] - Fat Static Library 빌드 (1/2)

2020/12/10 - [iOS/Tips] - Custom UserAgent 설정

2020/12/10 - [iOS/Tips] - CocoaPods 설치 및 제거

2020/12/10 - [iOS/Tips] - Clang diagnostic 경고 무시하기

2020/12/10 - [개발노트] - Bluetooth UUID

2020/12/08 - [개발노트] - 모바일 앱 메모리덤프 이슈 해결방법

2020/12/08 - [프로그래밍/Java Script] - Android, iOS 앱 설치여부 체크 및 스토어 이동

2020/08/21 - [Android/Tips] - aab파일 apk파일로 변환

2020/08/11 - [iOS/Swift] - WKWebView 화면 출력 완료 이벤트

2020/08/06 - [iOS/Tips] - 개발관련 폴더 경로

2020/07/19 - [Android/Tips] - 안드로이드 원격 디버깅 방법

2020/07/18 - [Android/Tips] - Cannot convert string value 'JETPACK_COMPOSE' to an enum value of type 'com.android.builder.model.AndroidGradlePluginProjectFlags$BooleanFlag' (valid case insensitive values: APPLICATION_R_CLASS_CONSTANT_IDS, TEST_R_CLASS_CONSTANT_IDS, TRANSITIVE_R_CLASS)

2020/07/18 - [Android/Tips] - OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

2020/07/17 - [iOS/Tips] - 웹에서 iOS 앱 설치여부 체크

반응형

'개발 > iOS' 카테고리의 다른 글

웹뷰에서 javascript 함수 동기식 호출  (0) 2020.12.10
Fat Static Library 빌드 (2/2)  (0) 2020.12.10
Custom UserAgent 설정  (0) 2020.12.10
CocoaPods 설치 및 제거  (0) 2020.12.10
Clang diagnostic 경고 무시하기  (0) 2020.12.10
블로그 이미지

SKY STORY

,