iOS2013. 6. 28. 19:35


iOS UIWebView Page loading flow 테스트 결과

didStartLoad delegate에서 webVIew.request.URL은 이전 페이지의 URL이거나 비어있다.

페이지로딩이 리다이렉트될때

 1. shouldStartLoading (requestURL is target page)

 2. didStartLoading

 3. shouldStartLoading (requestURL is redirect target)

 4. didFinishLoad (request.URL is redirect target)

 Note : 두번째 didStartLoading이 호출되지 않는다.


iframe을 포함한 페이지의 로딩시

 1. shouldStartLoading (requestURL is main page)

 2. didStartLoading

 3. shouldStartLoading (requestURL is one of the iframes)

 4. didStartLoading

 5. didFinishLoad

 6. didFinishLoad

Note didFinishLoad가 어떤 didStartLoad에 대응되는지 알 방법이 없음.


window.history.go(-1)가 호출될때

 1. didStartLoading

 2. didFinishLoad

 Note shouldStartLoading가 호출되지 않는다.  iOS6에서는 호출된다.


location.reload()호출시

 1. shouldStartLoading

 2. didStartLoading

 3. didFinishLoad


iframe페이지 로딩이 실패한 경우:

 1. shouldStart (main page)

 2. didStart

 3. shouldStart (iframe)

 4. didStart

 5. didFailWithError

 6. didFinish


잘못된 URL로 인해 iframe로딩이 실패한 경우

 1. shouldStart (main page)

 2. didStart

 3. shouldStart (iframe)

 5. didFailWithError

 6. didFinish

didStart가 누락된다. 해결하려면 shouldStart에서 URL을 체크하고 문제가 있으면 NO를 리턴하면 된다.


잘못된 URL접근인 경우

 1. shouldStart (main page)

 2. didFailWithError


Posted by 삼스
iOS2013. 6. 14. 12:22

Variable                                  Example
PATH                                      "/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:/Developer/usr/bin:/usr/bin:/bin:/usr/sbin:/sbin"
LANG                                      en_US.US-ASCII
IPHONEOS_DEPLOYMENT_TARGET                4.1
ACTION                                    build
AD_HOC_CODE_SIGNING_ALLOWED               NO
ALTERNATE_GROUP                           staff
ALTERNATE_MODE                            u+w,go-w,a+rX
ALTERNATE_OWNER                           username
ALWAYS_SEARCH_USER_PATHS                  YES
APPLE_INTERNAL_DEVELOPER_DIR              /AppleInternal/Developer
APPLE_INTERNAL_DIR                        /AppleInternal
APPLE_INTERNAL_DOCUMENTATION_DIR          /AppleInternal/Documentation
APPLE_INTERNAL_LIBRARY_DIR                /AppleInternal/Library
APPLE_INTERNAL_TOOLS                      /AppleInternal/Developer/Tools
APPLY_RULES_IN_COPY_FILES                 NO
ARCHS                                     "armv6 armv7"
ARCHS_STANDARD_32_64_BIT                  "armv6 armv7"
ARCHS_STANDARD_32_BIT                     "armv6 armv7"
ARCHS_UNIVERSAL_IPHONE_OS                 armv7
AVAILABLE_PLATFORMS                       "iphonesimulator macosx iphoneos"
BUILD_COMPONENTS                          "headers build"
BUILD_DIR                                 "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath"
BUILD_ROOT                                "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath"
BUILD_STYLE                    
BUILD_VARIANTS                             normal
BUILT_PRODUCTS_DIR                         "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos"
CACHE_ROOT                                 /var/folders/2x/rvb2r9s16mq6r318zxvn0lk80000gn/C/com.apple.Xcode.501
CCHROOT                                    /var/folders/2x/rvb2r9s16mq6r318zxvn0lk80000gn/C/com.apple.Xcode.501
CHMOD                                      /bin/chmod
CHOWN                                      /usr/sbin/chown
CLASS_FILE_DIR                             "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/JavaClasses"
CLEAN_PRECOMPS                             YES
CLONE_HEADERS                              NO
CODESIGNING_FOLDER_PATH                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/InstallationBuildProductsLocation/Applications/project.app"
CODE_SIGNING_ALLOWED                       YES
CODE_SIGNING_REQUIRED                      YES
CODE_SIGN_CONTEXT_CLASS                    XCiPhoneOSCodeSignContext
CODE_SIGN_IDENTITY                         "iPhone Distribution"
COMBINE_HIDPI_IMAGES                       NO
COMPOSITE_SDK_DIRS                         /var/folders/2x/rvb2r9s16mq6r318zxvn0lk80000gn/C/com.apple.Xcode.501/CompositeSDKs
COMPRESS_PNG_FILES                         YES
CONFIGURATION                              Distribution
CONFIGURATION_BUILD_DIR                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos"
CONFIGURATION_TEMP_DIR                     "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos"
CONTENTS_FOLDER_PATH                       project.app/Contents
COPYING_PRESERVES_HFS_DATA                 NO
COPY_PHASE_STRIP                           YES
COPY_RESOURCES_FROM_STATIC_FRAMEWORKS      YES
CP                                         /bin/cp
CURRENT_ARCH                               armv7
CURRENT_VARIANT                            normal
DEAD_CODE_STRIPPING                        YES
DEBUGGING_SYMBOLS                          YES
DEBUG_INFORMATION_FORMAT                   dwarf-with-dsym
DEPLOYMENT_LOCATION                        YES
DEPLOYMENT_POSTPROCESSING                  YES
DERIVED_FILES_DIR                          "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/DerivedSources"
DERIVED_FILE_DIR                           "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/DerivedSources"
DERIVED_SOURCES_DIR                        "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/DerivedSources"
DEVELOPER_APPLICATIONS_DIR                 /Developer/Applications
DEVELOPER_BIN_DIR                          /Developer/usr/bin
DEVELOPER_DIR                              /Developer
DEVELOPER_FRAMEWORKS_DIR                   /Developer/Library/Frameworks
DEVELOPER_FRAMEWORKS_DIR_QUOTED            "\"/Developer/Library/Frameworks\""
DEVELOPER_LIBRARY_DIR                      /Developer/Library
DEVELOPER_SDK_DIR                          /Developer/SDKs
DEVELOPER_TOOLS_DIR                        /Developer/Tools
DEVELOPER_USR_DIR                          /Developer/usr
DEVELOPMENT_LANGUAGE                       English
DOCUMENTATION_FOLDER_PATH                  project.app/English.lproj/Documentation
DO_HEADER_SCANNING_IN_JAM                  NO
DSTROOT                                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/InstallationBuildProductsLocation"
DWARF_DSYM_FILE_NAME                       project.app.dSYM
DWARF_DSYM_FILE_SHOULD_ACCOMPANY_PRODUCT   NO
DWARF_DSYM_FOLDER_PATH                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos"
EFFECTIVE_PLATFORM_NAME                    -iphoneos
EMBEDDED_PROFILE_NAME                      embedded.mobileprovision
ENABLE_HEADER_DEPENDENCIES                 YES
ENABLE_OPENMP_SUPPORT                      NO
ENTITLEMENTS_ALLOWED                       YES
ENTITLEMENTS_REQUIRED                      YES
EXCLUDED_INSTALLSRC_SUBDIRECTORY_PATTERNS  ".svn CVS"
EXECUTABLES_FOLDER_PATH                    project.app/Executables
EXECUTABLE_FOLDER_PATH                     project.app
EXECUTABLE_NAME                            project
EXECUTABLE_PATH                            project.app/project
FILE_LIST                                  "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/Objects/LinkFileList"
FIXED_FILES_DIR                            "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/FixedFiles"
FRAMEWORKS_FOLDER_PATH                     project.app/Frameworks
FRAMEWORK_FLAG_PREFIX                      -framework
FRAMEWORK_SEARCH_PATHS                     "\"/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos\" "
FRAMEWORK_VERSION                          A
FULL_PRODUCT_NAME                          project.app
GCC3_VERSION                               3.3
GCC_C_LANGUAGE_STANDARD                    gnu99
GCC_INLINES_ARE_PRIVATE_EXTERN             YES
GCC_PFE_FILE_C_DIALECTS                    "c objective-c c++ objective-c++"
GCC_PRECOMPILE_PREFIX_HEADER               YES
GCC_PREFIX_HEADER                          project/Prefix.pch
GCC_PREPROCESSOR_DEFINITIONS               "NDEBUG DISTRIBUTION_BUILD=1 KK_TARGET=0x000F0"
GCC_SYMBOLS_PRIVATE_EXTERN                 YES
GCC_THUMB_SUPPORT                          YES
GCC_TREAT_WARNINGS_AS_ERRORS               NO
GCC_VERSION                                com.apple.compilers.llvm.clang.1_0
GCC_VERSION_IDENTIFIER                     com_apple_compilers_llvm_clang_1_0
GCC_WARN_ABOUT_RETURN_TYPE                 YES
GCC_WARN_UNUSED_FUNCTION                   YES
GCC_WARN_UNUSED_VARIABLE                   YES
GENERATE_MASTER_OBJECT_FILE                NO
GENERATE_PKGINFO_FILE                      YES
GENERATE_PROFILING_CODE                    NO
GID                                        20
GROUP                                      staff
INPUT_FILE_BASE             Default
INPUT_FILE_DIR              "/Volumes/Development/Project Game/Project-v1/images"
INPUT_FILE_NAME             Default.png
INPUT_FILE_PATH             "/Volumes/Development/Project Game/Project-v1/images/Default.png"
SCRIPT_INPUT_FILE           "/Volumes/Development/Project Game/Project-v1/images/Default.png"
SCRIPT_OUTPUT_FILE_0        "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/DerivedSources/Default.png"

EXCLUDED_RECURSIVE_SEARCH_PATH_SUBDIRECTORIES              "*.nib *.lproj *.framework *.gch (*) CVS .svn .git *.xcodeproj *.xcode *.pbproj *.pbxproj"
HEADERMAP_INCLUDES_FLAT_ENTRIES_FOR_TARGET_BEING_BUILT     YES
HEADERMAP_INCLUDES_FRAMEWORK_ENTRIES_FOR_ALL_PRODUCT_TYPES YES
HEADERMAP_INCLUDES_NONPUBLIC_NONPRIVATE_HEADERS            YES
HEADERMAP_INCLUDES_PROJECT_HEADERS                         YES
HEADER_SEARCH_PATHS                  "\"/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos/include\" "
ICONV                                /usr/bin/iconv
INFOPLIST_EXPAND_BUILD_SETTINGS      YES
INFOPLIST_FILE                       project/Resources/Info.plist
INFOPLIST_OUTPUT_FORMAT              binary
INFOPLIST_PATH                       project.app/Info.plist
INFOPLIST_PREPROCESS                 NO
INFOSTRINGS_PATH                     project.app/English.lproj/InfoPlist.strings
INPUT_FILE_REGION_PATH_COMPONENT                    
INPUT_FILE_SUFFIX                    .png
INSTALL_DIR                          "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/InstallationBuildProductsLocation/Applications"
INSTALL_GROUP                        staff
INSTALL_MODE_FLAG                    u+w,go-w,a+rX
INSTALL_OWNER                        username
INSTALL_PATH                         /Applications
INSTALL_ROOT                         "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/InstallationBuildProductsLocation"
JAVAC_DEFAULT_FLAGS                  "-J-Xms64m -J-XX:NewSize=4M -J-Dfile.encoding=UTF8"
JAVA_APP_STUB                        /System/Library/Frameworks/JavaVM.framework/Resources/MacOS/JavaApplicationStub
JAVA_ARCHIVE_CLASSES                 YES
JAVA_ARCHIVE_TYPE                    JAR
JAVA_COMPILER                        /usr/bin/javac
JAVA_FOLDER_PATH                     project.app/Java
JAVA_FRAMEWORK_RESOURCES_DIRS        Resources
JAVA_JAR_FLAGS                       cv
JAVA_SOURCE_SUBDIR                   .
JAVA_USE_DEPENDENCIES                YES
JAVA_ZIP_FLAGS                       -urg
JIKES_DEFAULT_FLAGS                  "+E +OLDCSO"
KEEP_PRIVATE_EXTERNS                 NO
LD_GENERATE_MAP_FILE                 NO
LD_MAP_FILE_PATH                     "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/project-LinkMap-normal-armv7.txt"
LD_NO_PIE                            NO
LD_OPENMP_FLAGS                      -fopenmp
LEGACY_DEVELOPER_DIR                 /Developer/Library/Xcode/PrivatePlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer
LEX                                  /Developer/usr/bin/lex
LIBRARY_FLAG_NOSPACE                 YES
LIBRARY_FLAG_PREFIX                  -l
LIBRARY_SEARCH_PATHS                 "\"/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos\"  \"/Volumes/Development/Project Game/Project-v1/FlurryLib\""
LINKER_DISPLAYS_MANGLED_NAMES        NO
LINK_FILE_LIST_normal_armv6          "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/Objects-normal/armv6/project.LinkFileList"
LINK_FILE_LIST_normal_armv7          "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/Objects-normal/armv7/project.LinkFileList"
LINK_WITH_STANDARD_LIBRARIES         YES
LOCALIZED_RESOURCES_FOLDER_PATH      project.app/English.lproj
LOCAL_ADMIN_APPS_DIR                 /Applications/Utilities
LOCAL_APPS_DIR                       /Applications
LOCAL_DEVELOPER_DIR                  /Library/Developer
LOCAL_LIBRARY_DIR                    /Library
MACH_O_TYPE                          mh_execute
MAC_OS_X_PRODUCT_BUILD_VERSION       11A511
MAC_OS_X_VERSION_ACTUAL              1070
MAC_OS_X_VERSION_MAJOR               1070
MAC_OS_X_VERSION_MINOR               0700
NATIVE_ARCH                          armv6
NATIVE_ARCH_32_BIT                   i386
NATIVE_ARCH_64_BIT                   x86_64
NATIVE_ARCH_ACTUAL                   x86_64
NO_COMMON                            YES
OBJECT_FILE_DIR                      "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/Objects"
OBJECT_FILE_DIR_normal               "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/Objects-normal"
OBJROOT                              "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath"
ONLY_ACTIVE_ARCH                     NO
OPTIMIZATION_LEVEL                   0
OS                                   MACOS
OSAC                                 /usr/bin/osacompile
OTHER_CFLAGS                         -DNS_BLOCK_ASSERTIONS=1
OTHER_CPLUSPLUSFLAGS                 -DNS_BLOCK_ASSERTIONS=1
OTHER_INPUT_FILE_FLAGS                    
OTHER_LDFLAGS                        -lz
PACKAGE_TYPE                         com.apple.package-type.wrapper.application
PASCAL_STRINGS                       YES
PATH_PREFIXES_EXCLUDED_FROM_HEADER_DEPENDENCIES  "/usr/include /usr/local/include /System/Library/Frameworks /System/Library/PrivateFrameworks /Developer/Headers /Developer/SDKs /Developer/Platforms"
PBDEVELOPMENTPLIST_PATH              project.app/pbdevelopment.plist
PFE_FILE_C_DIALECTS                  "c objective-c c++ objective-c++"
PKGINFO_FILE_PATH                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/PkgInfo"
PKGINFO_PATH                         project.app/PkgInfo
PLATFORM_DEVELOPER_APPLICATIONS_DIR  /Developer/Platforms/iPhoneOS.platform/Developer/Applications
PLATFORM_DEVELOPER_BIN_DIR           /Developer/Platforms/iPhoneOS.platform/Developer/usr/bin
PLATFORM_DEVELOPER_LIBRARY_DIR       /Developer/Library/Xcode/PrivatePlugIns/Xcode3Core.ideplugin/Contents/SharedSupport/Developer/Library
PLATFORM_DEVELOPER_SDK_DIR           /Developer/Platforms/iPhoneOS.platform/Developer/SDKs
PLATFORM_DEVELOPER_TOOLS_DIR         /Developer/Platforms/iPhoneOS.platform/Developer/Tools
PLATFORM_DEVELOPER_USR_DIR           /Developer/Platforms/iPhoneOS.platform/Developer/usr
PLATFORM_DIR                         /Developer/Platforms/iPhoneOS.platform
PLATFORM_NAME                        iphoneos
PLATFORM_PREFERRED_ARCH              i386
PLATFORM_PRODUCT_BUILD_VERSION       8H7
PLIST_FILE_OUTPUT_FORMAT             binary
PLUGINS_FOLDER_PATH                  project.app/PlugIns
PRECOMPS_INCLUDE_HEADERS_FROM_BUILT_PRODUCTS_DIR                    YES
PRECOMP_DESTINATION_DIR              "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/PrefixHeaders"
PRESERVE_DEAD_CODE_INITS_AND_TERMS   NO
PRIVATE_HEADERS_FOLDER_PATH          project.app/PrivateHeaders
PRODUCT_NAME                         project
PRODUCT_SETTINGS_PATH                "/Volumes/Development/Project Game/Project-v1/project/Resources/Info.plist"
PRODUCT_TYPE                         com.apple.product-type.application
PROFILING_CODE                       NO
PROJECT                              project
PROJECT_DERIVED_FILE_DIR             "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/DerivedSources"
PROJECT_DIR                          "/Volumes/Development/Project Game/Project-v1"
PROJECT_FILE_PATH                    "/Volumes/Development/Project Game/Project-v1/project.xcodeproj"
PROJECT_NAME                         project
PROJECT_TEMP_DIR                     "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build"
PROVISIONING_PROFILE_REQUIRED        YES
PUBLIC_HEADERS_FOLDER_PATH           project.app/Headers
RECURSIVE_SEARCH_PATHS_FOLLOW_SYMLINKS   YES
REMOVE_CVS_FROM_RESOURCES            YES
REMOVE_GIT_FROM_RESOURCES            YES
REMOVE_SVN_FROM_RESOURCES            YES
RESOURCE_RULES_REQUIRED              YES
REZ_COLLECTOR_DIR                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/ResourceManagerResources"
REZ_OBJECTS_DIR                      "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/ResourceManagerResources/Objects"
REZ_SEARCH_PATHS                     "\"/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos\" "
RUN_CLANG_STATIC_ANALYZER            NO
SCAN_ALL_SOURCE_FILES_FOR_INCLUDES   NO
SCRIPTS_FOLDER_PATH                  project.app/Scripts
SCRIPT_INPUT_FILE                    "/Volumes/Development/Project Game/Project-v1/fonts/helvetica-black-hd.png"
SCRIPT_OUTPUT_FILE_0                 "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build/DerivedSources/helvetica-black-hd.png"
SCRIPT_OUTPUT_FILE_COUNT             1
SDKROOT                              /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk
SDK_DIR                              /Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.3.sdk
SDK_NAME                             iphoneos4.3
SDK_PRODUCT_BUILD_VERSION            8H7
SED                                  /usr/bin/sed
SEPARATE_STRIP                       NO
SEPARATE_SYMBOL_EDIT                 NO
SET_DIR_MODE_OWNER_GROUP            YES
SET_FILE_MODE_OWNER_GROUP           NO
SHALLOW_BUNDLE                      YES
SHARED_DERIVED_FILE_DIR             "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath/Distribution-iphoneos/DerivedSources"
SHARED_FRAMEWORKS_FOLDER_PATH       project.app/SharedFrameworks
SHARED_PRECOMPS_DIR                 /Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/Build/PrecompiledHeaders
SHARED_SUPPORT_FOLDER_PATH          project.app/SharedSupport
SKIP_INSTALL                        NO
SOURCE_ROOT                         "/Volumes/Development/Project Game/Project-v1"
SRCROOT                             "/Volumes/Development/Project Game/Project-v1"
STRINGS_FILE_OUTPUT_ENCODING        binary
STRIP_INSTALLED_PRODUCT             YES
STRIP_STYLE                         all
SUPPORTED_DEVICE_FAMILIES           1,2
SUPPORTED_PLATFORMS                 "iphonesimulator iphoneos"
SYMROOT                             "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/BuildProductsPath"
SYSTEM_ADMIN_APPS_DIR               /Applications/Utilities
SYSTEM_APPS_DIR                     /Applications
SYSTEM_CORE_SERVICES_DIR            /System/Library/CoreServices
SYSTEM_DEMOS_DIR                    /Applications/Extras
SYSTEM_DEVELOPER_APPS_DIR           /Developer/Applications
SYSTEM_DEVELOPER_BIN_DIR            /Developer/usr/bin
SYSTEM_DEVELOPER_DEMOS_DIR          "/Developer/Applications/Utilities/Built Examples"
SYSTEM_DEVELOPER_DIR                /Developer
SYSTEM_DEVELOPER_DOC_DIR            "/Developer/ADC Reference Library"
SYSTEM_DEVELOPER_GRAPHICS_TOOLS_DIR "/Developer/Applications/Graphics Tools"
SYSTEM_DEVELOPER_JAVA_TOOLS_DIR     "/Developer/Applications/Java Tools"
SYSTEM_DEVELOPER_PERFORMANCE_TOOLS_DIR   "/Developer/Applications/Performance Tools"
SYSTEM_DEVELOPER_RELEASENOTES_DIR   "/Developer/ADC Reference Library/releasenotes"
SYSTEM_DEVELOPER_TOOLS              /Developer/Tools
SYSTEM_DEVELOPER_TOOLS_DOC_DIR      "/Developer/ADC Reference Library/documentation/DeveloperTools"
SYSTEM_DEVELOPER_TOOLS_RELEASENOTES_DIR   "/Developer/ADC Reference Library/releasenotes/DeveloperTools"
SYSTEM_DEVELOPER_USR_DIR            /Developer/usr
SYSTEM_DEVELOPER_UTILITIES_DIR      /Developer/Applications/Utilities
SYSTEM_DOCUMENTATION_DIR            /Library/Documentation
SYSTEM_LIBRARY_DIR                  /System/Library
TARGETED_DEVICE_FAMILY              1
TARGETNAME                          Project
TARGET_BUILD_DIR                    "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/InstallationBuildProductsLocation/Applications"
TARGET_NAME                         Project
TARGET_TEMP_DIR                     "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build"
TEMP_DIR                            "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build"
TEMP_FILES_DIR                      "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build"
TEMP_FILE_DIR                       "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath/project.build/Distribution-iphoneos/Project.build"
TEMP_ROOT                           "/Users/username/Library/Developer/Xcode/DerivedData/project-dxdgjvgsvvbhowgjqouevhmvgxgf/ArchiveIntermediates/Project Distribution/IntermediateBuildFilesPath"
TEST_AFTER_BUILD                    NO
UID                                 501
UNLOCALIZED_RESOURCES_FOLDER_PATH   project.app    UNSTRIPPED_PRODUCT           NO
USER                         username
USER_APPS_DIR                /Users/username/Applications
USER_HEADER_SEARCH_PATHS     project/libs
USER_LIBRARY_DIR             /Users/username/Library
USE_DYNAMIC_NO_PIC           YES
USE_HEADERMAP                YES
USE_HEADER_SYMLINKS          NO
VALIDATE_PRODUCT             YES
VALID_ARCHS                  "armv6 armv7"
VERBOSE_PBXCP                NO
VERSIONPLIST_PATH            project.app/version.plist
VERSION_INFO_BUILDER         username
VERSION_INFO_FILE            project_vers.c
VERSION_INFO_STRING          "\"@(#)PROGRAM:project  PROJECT:project-\""
WRAPPER_EXTENSION            app
WRAPPER_NAME                 project.app
WRAPPER_SUFFIX               .app
XCODE_APP_SUPPORT_DIR        /Developer/Library/Xcode
XCODE_PRODUCT_BUILD_VERSION  4B110
XCODE_VERSION_ACTUAL         0410
XCODE_VERSION_MAJOR          0400
XCODE_VERSION_MINOR          0410
YACC                        /Developer/usr/bin/yacc
출처: https://samse.tistory.com/entry/XCode-build-variables [고 투 더 멘토:티스토리]

 

Posted by 삼스
iOS2013. 6. 12. 10:37


Google Tool Box for Mac에서 제공하는 _GTMDebugLog

log4j를 cocoa에 포팅한 log4cocoa 정도가 있겠다.


먼저 GTM의 logging방식을 살펴보겠다.


GTM for Mac은 구글개발자들이 사용하는 맥개발용 라이브러리들을 모아놓은 프로젝트이다.

이 중에 로그를 위해 만들어 놓은게 _GTMDevLog, _GTMDevAssert인데 기능자체는 상당히 간단하다.

GTMDefines.h에 다음과 같이 정의되어 있다.

#ifndef _GTMDevLog

#ifdef DEBUG

  #define _GTMDevLog(...) NSLog(__VA_ARGS__)

#else

  #define _GTMDevLog(...) do { } while (0)

#endif

#endif // _GTMDevLog

#ifndef _GTMDevAssert

// we directly invoke the NSAssert handler so we can pass on the varargs

// (NSAssert doesn't have a macro we can use that takes varargs)

#if !defined(NS_BLOCK_ASSERTIONS)

  #define _GTMDevAssert(condition, ...)                                       \

    do {                                                                      \

      if (!(condition)) {                                                     \

        [[NSAssertionHandler currentHandler]                                  \

            handleFailureInFunction:[NSString stringWithUTF8String:__PRETTY_FUNCTION__] \

                               file:[NSString stringWithUTF8String:__FILE__]  \

                         lineNumber:__LINE__                                  \

                        description:__VA_ARGS__];                             \

      }                                                                       \

    } while(0)

#else // !defined(NS_BLOCK_ASSERTIONS)

  #define _GTMDevAssert(condition, ...) do { } while (0)

#endif // !defined(NS_BLOCK_ASSERTIONS)

#endif // _GTMDevAssert


NSLog와 NSAssertionHandler를 연결해 두었고 DEBUG빌드시에만 실제 로거가 동작하도록 되어 있다.

다만 _GTMDevLog를 실제 프로젝트에서 리플랙션을 통해 동작방식을 정의할 수 있도록 샘플이 있다.


GTM_Prefix.pch에 다음과 같이 변경하여 오버라이딩이 가능하다.

// This turns on unit test logging so that we can track unittests if we are

// doing them. See GTMUnitTestDevLog.h for details.

// (_GTMUnitTestDevLog comes from GTMDevLogUnitTestingBridge.m)

#define _GTMDevLog _GTMUnitTestDevLog


별도의 브릿지역할을 하는 GTMDevLogUnitTestingBridge.m에 다음과 같이 정의되어 있는데 GTMUnitTestDevLog라는 클래스명으로 리플렉션하여 로그동작을 오버라이드 하고 있다.

void _GTMUnitTestDevLog(NSString *format, ...) {

  Class devLogClass = NSClassFromString(@"GTMUnitTestDevLog");

  va_list argList;

  va_start(argList, format);

  if (devLogClass) {

    [devLogClass log:format args:argList];

  } else {

    NSLogv(format, argList); // COV_NF_LINE the class is in all our unittest setups

  }

  va_end(argList);

}

이 로깅 방식은 사용이 간단하지만 로그레벨을 부여할수 없는것이 단점이다.






Posted by 삼스
Windows2013. 5. 23. 17:31




C DLL이 다음 처럼 2개의 함수를 노출한다고 할 때

DLLFunction int addint(int n1, int n2)

{

   return n1 + n2;

}

DLLFunction int addchar(char* s1, char* s2, char* added)

{

   sprintf(added, "%s%s", s1, s2);

   return strlen(added);

}


C#에서는 다음 코드와 같이 사용 가능하다.

여기서 요점은 c data type과 C# data type을 매칭하는것인데. 이 때 메모리를 할당하여 포인터를 전달하거나 struct 데이터를 전달할 경우 Marsal 클래스를 사용해야 한다. (참조 : http://rainiac.com/dev/index.php/c-interop-c%EA%B3%BC-c-api%EC%9D%98-%EC%83%81%ED%98%B8%EC%9A%B4%EC%98%81/)


using System.Runtime.InteropServices; 


// 빈 페이지 항목 템플릿에 대한 설명은 http://go.microsoft.com/fwlink/?LinkId=234238에 나와 있습니다.



namespace DllTestApp1

{

    class Dll

    {

        [DllImport("Win32Project1.dll")]

        public static extern int addint(int n1, int n2);

        [DllImport("Win32Project1.dll")]

        public static extern int addchar(StringBuilder s1, StringBuilder s2, StringBuilder s3);   

    }



    /// <summary>

    /// 자체에서 사용하거나 프레임 내에서 탐색할 수 있는 빈 페이지입니다.

    /// </summary>

    public sealed partial class MainPage : Page

    {

        public MainPage()

        {

            this.InitializeComponent();

        }


        /// <summary>

        /// 이 페이지가 프레임에 표시되려고 할 때 호출됩니다.

        /// </summary>

        /// <param name="e">페이지에 도달한 방법을 설명하는 이벤트 데이터입니다. Parameter

        /// 속성은 일반적으로 페이지를 구성하는 데 사용됩니다.</param>

        protected override void OnNavigatedTo(NavigationEventArgs e)

        {

        }




        // add int

        private void Button_Click_1(object sender, RoutedEventArgs e)

        {

            int sum = Dll.addint((int)10, (int)200);

        }


        // add char

        private void Button_Click_2(object sender, RoutedEventArgs e)

        {


            StringBuilder aa = new StringBuilder("aa");

            StringBuilder bb = new StringBuilder("bb");

            StringBuilder added = new StringBuilder();

            Dll.addchar(aa, bb, added);

        }

    }

}


Posted by 삼스
Android/App개발2013. 3. 7. 11:20


안드로이드 Bluetooth 프로그래밍을 위해 http://developer.android.com/guide/topics/connectivity/bluetooth.html의 내용을 정리함.

안드로이드 플랫폼은 블루투스네트웍스택을 제공하여 다음의 블루투스의 기능을 제공한다.

- 다른 디바이스의 스캔

- 페어링을 위해 로칼디바이스에 쿼리 

- RFCOMM채널 연결 가능

- 서비스 디스커버리를 통한 타디바이스 연결

- 디바이스간 데이터 전송

- 다중연결 관리


기초

블루투스셋업, 페어링된 또는 유효한 디바이스 찾기, 연결하기 그리고 데이터 전송하기에 대한 기초적인 내용을 기술하겠다.

android.bluetooth패키지에 모든 API들이 정의되어 있다. 다음에 설명되는 클래스들이 대표적인 클래스들이다.

BluetoothAdapter

  로컬블루투스어댑터를 대표한다. 이 객체를 통해서 디바이스를 찾고 연결하고 디바이스를 활성화하여 통신을 수행하는등의 작업이 가능하다.

BluetoothDevice

  원격블루투스디바이스를 대표한다. 이 객체를 통해 블루투스소켓을 통한 연결이나 디바이스의 속성정보를 요청할 수 있다.

BluetoothSocket

  블루투스소켓의 인터페이스를 대표한다. TCP socket과 유사하다. 입출력스트림을 통해 다른 디바이스와 데이터를 주고받을 수 있다.

BluetoothServerSocket

  들어오는 요청을 수신할 수 있는 서버소캣을 대표한다. TCP ServerSocket과 유사하다. 

BluetoothClass

  블루투스디바이스의 특성과 사양을 나타낸다. 읽기전용속성이며 major, minor 디바이스 클래스로 디바이스의 성격을 규정한다.  

BluetoothProfile

  블루투스프로파일을 나타낸다. 블루투스기반의 통신을 위한 무선인터페이스 규격을 말한다. 예를 들어 핸즈프리 프로파일같은 것을 말한다. 더 자세한 내용은 http://developer.android.com/guide/topics/connectivity/bluetooth.html#Profiles 를 참조하라.

BluetoothHeadset

  모바일폰을 위한 블루투스헤드셋을 지원한다. 핸즈프리(v1.5)프로파일을 포함한다.

BluetoothA2dp

  오디오전송을 위한 품질을 정의한다. A2DP(Advanced Audio Distribution Profile)

BluetoothHealth

  건강관련 디바이스 프로파일

BluetoothHealthCallback

  BluetoothHealth 콜백을 구현하기 위한 추상클래스. 애플리케이션의 등록상태나 블루투스채널의 변경이나 업데이트의 수신을 감지하기 위해 이 클래스를 반드시 구현해야 한다.

BluetoothHealthAppCOnfiguration

  Bluetooth Health 3rd-party애플리케이션을 health device에 연결하기 위한 설정

BluetoothProfile.ServiceListener

  Bluetooth 서비스가 연결 또는 차단되었을 때 BluetoothProfile IPC 클라이언트에 통지를 한다. 즉 내부에서 서비스는 각각의 프로파일로 동작한다.


블루투스 권환

BLUETOOTH와 BLUETOOTH_ADMIN 권한이 준비되어 있다.

BLUETOOTH : 블루투스통신을 위한 권한

BLUETOOTH_ADMIN :  디바이스 디스커버리나 장치설정등을 할 수 있는 권한.


블루투스 셋업

블루투스를 사용하기 전에 디바이스가 블루투스가 가능한지 살펴야 한다.

1. BluetoothAdapter를 얻어낸다.

  1. BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
    if (mBluetoothAdapter == null) {
       
    // Device does not support Bluetooth
    }

2. 블루투스를 활성화한다.

if (!mBluetoothAdapter.isEnabled()) {
   
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
    startActivityForResult
(enableBtIntent, REQUEST_ENABLE_BT);
}

위와 같이 호출하면 블루투스활성화여부 팝업이 뜨며 사용자가 확인을 선택하면 RESULT_OK가 onActivityResult()에서 리턴되고 그러지 않으면 RESULT_CANCELED가 리턴된다.

이 때 앱은 onPause와 onResume루틴을 타게 되니 유의한다.


디바이스 찾기

BluetoothAdapter를 통해 근처의 디바이스들을 찾을 수 있으며 페어링된 다바이스리스트도 얻을 수 있다.

디바이스디스커버리는 주변의 블루투스가 활성화되어 있는 디바이스들을 스캔한다. 그리고 각 디바이스의 정보를 수집한다. 수집이 가능한 디바이스는 블루투스가 활성화되어 있고 검색가능한 상태로 셋팅되어 있어야 한다. 그러면 검색되어 지고 디바이스명, 클래스 그리고 MAC주소가 수집이 가능하다. 이 정보를 기반으로 특정 디바이스를 선택하여 연결할 수 있다.

한번 연결이 이루어진 디바이스는 자동으로 페어링이 요청되게 된다. 디스커버리할때 저장된 MAC주소정보를 통해 디서커버리 단계 없이 바로 연결을 할 수 있다.

페어링과 연결은 한가지 차이점이 있다. 페어링은 두 디바이스가 서로 존재함을 인식하는 것이고 인증을 위해 공유된 link-key를 가지고 서로 암호화된 연결을 확립할 수 있다.

연결은 디바이스간에 RFCOMM채널을 공유하였다는 것이고 서로 데이터를 주고 받을 수 있다는 것이다. 페어링이 먼저 되어야 통신을 수행할 수 있다.

안드로이드가 탑재된 제품들은 discoverable이 꺼진 상태이다. 따라서 페어링을 위해 discoverable을 활성화하여야 한다. http://developer.android.com/guide/topics/connectivity/bluetooth.html#EnablingDiscoverability 를 참조하라.


페어링된 다바이스 얻기

디스커버리를 수행하기 전에 현재 페어링된 디바이스를 알아낼수 있다. getBondedDevices()메서드로 페어링된 디바이스들의 리스트를 얻을 수 있다.

Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
// If there are paired devices
if (pairedDevices.size() > 0) {
   
// Loop through paired devices
   
for (BluetoothDevice device : pairedDevices) {
       
// Add the name and address to an array adapter to show in a ListView
        mArrayAdapter
.add(device.getName() + "\n" + device.getAddress());
   
}
}

검색된 디바이스에는 연결을 위한 MAC주소정보가 포함되어 있으며 연결하기는 다음을 참조하라

http://developer.android.com/guide/topics/connectivity/bluetooth.html#ConnectingDevices


디바이스 디스커버리

startDiscovery()메서드를 수행하면 된다. 프로세스는 비동기로 동작하고 메서드는 바로 리턴된다. 

비동기로 진행되는 과정에 디바이스가 검색이 되면 ACTION_FOUND 인텐트가 브로드캐스트 되며 이 이벤트를 받기 위해 BroadcastReceiver를 사용해야 한다.

// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
   
public void onReceive(Context context, Intent intent) {
       
String action = intent.getAction();
       
// When discovery finds a device
       
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
           
// Get the BluetoothDevice object from the Intent
           
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
           
// Add the name and address to an array adapter to show in a ListView
            mArrayAdapter
.add(device.getName() + "\n" + device.getAddress());
       
}
   
}
};
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver
(mReceiver, filter); // Don't forget to unregister during onDestroy

디스커버리 과정은 전원을 많이 소비사는 과정이므로 검색이 다 끝나면 반드시 cancelDiscovery()를 호출해주어야 한다. 그리고 연결이 되어 있는 상태에서 디스커버리는 통신데이터 bandwidth를 현저하기 떨어뜨리기 때문에 연결중에는 디스커버리를 하지 않아야 한다.

디스커버러블 활성화

ACTION_REQUEST_DISCOVERABLE 액션인텐트를 startActivityForResult로 호출한다. EXTRA_DISCOVERABLE_DURATION 으로 탐색시간을 파라메터로 넘길 수 있다. 최대시간은 3600초이고 0이하는 내부적으로 120초로 자동 셋팅된다. 다음은 300초로 셋팅한 예이다.

Intent discoverableIntent = new
Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent
.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity
(discoverableIntent);

디바이스가 블루투스가 활성화가 안되어 있다면 자동으로 활성화후 진행한다.

디스커버러블모드는 백그라운드에서 지정한 시간만큼 유지되었다가 끝나게 된다. 만일 이 상태변화를 처리하고 싶다면 ACTION_SCAN_MODE_CHANGED인텐트의 리시버를 통해서 처리하면 된다. 이 인텐트는 추가정보로 EXTRA_SCAN_MODE, EXTRA_PREVIOUS_SCAN_MODE로 현재와 이전 스캔모드를 얻을 수 있다. 

모드는 3가지이다.

- SCAN_MODE_CONNECTABLE_DISCOVERABLE :    디바이스가 둘다 가능한 상태

- SCAN_MODE_CONNECTABLE :  디스커버러블모드는 아니고 연결은 가능한 상태.

-  SCAN_MODE_NONE : 둘다 안되는 상태

디바이스와 이미 연결이 초기화된 상태이면 굳이 디스커버러블을 활성화할 필요는 없다. 디스커버러블을 활성화하는 경우는 앱이 서버소켓을 제공하여 연결시도를 허락하기 위한 경우만 해당된다. 왜냐하면 원격디바이스들은 연결이 가능해지기 이전에 먼저 검색이 가능해야 하기 때문이다.


디바이스 연결

앱이 두단말간에 연결을 생성하기 위해서 서버와 클라이언트단을 모두 구현해야 한다. 하나는 서버가 되어서 대기하고 하나는 연결을 시도해야 하기 때문이다. 연결시 사용하는 정보는 서버의 MAC주소가 된다. 서버와 단말이 둘다 동일 RFCOMM채널상에서 BluetoothSocket으로 연결되면 상호간에 연결된것으로 간주된다. 이 때 입출력스트림을 통해 데이터를 주고받을 수 있다. 

서버와 클라이언트 디바이스는 각각 다른 방식으로 요구되는 BluetoothSocket을 얻는다. 서버는 요청받은 연결을 허락했을 때 얻어지고 클라이언트는 서버와 RFCOMM채널이 열렸을 때 얻어진다.

두 단말이 모두 자동으로 서버모드로 대기하고 서로간에 연결을 시도하는 방식과 명시적으로 하나는 호스트로써 서버로 대기하고 다른 하나가 연결을 시도하는 방식이 있다.

두 디바이스가 페어링된적이 없으면 안드로이드는 자동으로 페어링요청 통지나 팝업을 연결과정에 띄운다. 그래서 연결시도과정에 두 단말이 페어링된적이 있는지 알 필요가 없다. 연결시도는 페어링과정이 끝난 이후 계속 진행된다.


서버 연결

BluetoothServerSocket으로 서버로 동작시킬 수 있다. 서버소켓은 연결요청을 받아들이기 위한것이다.

1. BluetoothServerSocket을 얻는다.

   lisetnUsingRfcommWithServiceRecord(String, UUID)로 얻는다. String는 서비스명이고 UUID는 클라이언트디바이스와 연결 동의에 기반으로 사용된다. 다시 말해 클라이언트디바이스가 연결을 시도할 때 UUID가 전달되어진다. 다음단계에서 UUID는 서로 맷치가 되어야 한다.

2. accept()메서드로 연결요청을 대기한다.

  연결이 허용되거나 예외가 발생할 때 까지 이 메서드는 블럭된다.  클라이언트의 연결요청이 UUID가 일치하였을 때만 accept가 성공하고 BluetoothSocket을 리턴한다.

3. 더이상 연결을 허용하지 않을거라면 close()를 호출한다.

  서버소켓을 종료하고 모든 리소스를 해재한다. 연결된 상태는 유지된다.  TCP/IP와 다르게 RFCOMM은 하나의 채널에 하나의 연결만 허용한다. 따라서 accept()로 연결이 성립되면 서버소켓을 close()로 닫아준다.

accept는 Main activity에서 호출하지 않아야 블럭되는것을 방지할 수 있다. 블럭중에 중단하려면 다른 스레드에서 close()를 호출하면 된다.

다음은 서버구현의 예이다.

private class AcceptThread extends Thread {
   
private final BluetoothServerSocket mmServerSocket;
 
   
public AcceptThread() {
       
// Use a temporary object that is later assigned to mmServerSocket,
       
// because mmServerSocket is final
       
BluetoothServerSocket tmp = null;
       
try {
           
// MY_UUID is the app's UUID string, also used by the client code
            tmp
= mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
       
} catch (IOException e) { }
        mmServerSocket
= tmp;
   
}
 
   
public void run() {
       
BluetoothSocket socket = null;
       
// Keep listening until exception occurs or a socket is returned
       
while (true) {
           
try {
                socket
= mmServerSocket.accept();
           
} catch (IOException e) {
               
break;
           
}
           
// If a connection was accepted
           
if (socket != null) {
               
// Do work to manage the connection (in a separate thread)
                manageConnectedSocket
(socket);
                mmServerSocket
.close();
               
break;
           
}
       
}
   
}
 
   
/** Will cancel the listening socket, and cause the thread to finish */
   
public void cancel() {
       
try {
            mmServerSocket
.close();
       
} catch (IOException e) { }
   
}
}


클라이언트 연결

리모트디바이스와 연결하기 위해서는 일단 리모트디바이스객체를 얻어야 한다. 페어링된 디바이스를 얻거나 디스커버리 과정을 통해서 연결하고자 하는 BluetoothDevice를 얻어야 한다.

1. BluetoothDevice.createRfcommSocketToServiceRecord(UUID) 를 호출

  BluetoothSocket을 초기화한다. 이 때 서버디바이스에서 제공하는 UUID를 인자로 넘긴다. 이 값이 동일해야 연결이 성립된다.

2. connect()로 연결 시도

  UUID가 매칭되는 디바이스와 연결을 시도하고 성공하면 소켓을 리턴한다. 

connect()메서드가 블럭되는 호출이기 때문에 분리된 스레드에서 수행되어야 한다.

connect()과정 중에는 디스커버리가 진행되면 안된다. 만일 진행하게 되면 연결과정이 아주 느리게 진행되거나 실패하게 된다.

다음은 간략한 예제이다.

private class ConnectThread extends Thread {
   
private final BluetoothSocket mmSocket;
   
private final BluetoothDevice mmDevice;
 
   
public ConnectThread(BluetoothDevice device) {
       
// Use a temporary object that is later assigned to mmSocket,
       
// because mmSocket is final
       
BluetoothSocket tmp = null;
        mmDevice
= device;
 
       
// Get a BluetoothSocket to connect with the given BluetoothDevice
       
try {
           
// MY_UUID is the app's UUID string, also used by the server code
            tmp
= device.createRfcommSocketToServiceRecord(MY_UUID);
       
} catch (IOException e) { }
        mmSocket
= tmp;
   
}
 
   
public void run() {
       
// Cancel discovery because it will slow down the connection
        mBluetoothAdapter
.cancelDiscovery();
 
       
try {
           
// Connect the device through the socket. This will block
           
// until it succeeds or throws an exception
            mmSocket
.connect();
       
} catch (IOException connectException) {
           
// Unable to connect; close the socket and get out
           
try {
                mmSocket
.close();
           
} catch (IOException closeException) { }
           
return;
       
}
 
       
// Do work to manage the connection (in a separate thread)
        manageConnectedSocket
(mmSocket);
   
}
 
   
/** Will cancel an in-progress connection, and close the socket */
   
public void cancel() {
       
try {
            mmSocket
.close();
       
} catch (IOException e) { }
   
}
}


연결관리

디바이스간 연결이 완료되면 BluetoothSocket을 각각 소유하게 된다. 이넘을 통해서 데이터를 주고받을 수 있다.

1. 소켓으로부터 InputStream과 OutputStream을 얻는다.

2.  read(byte[]), write(byte[])로 읽거나 쓰면 끝...

두 메서드 모두 블럭되기 때문에 스레드로 분리되어야 한다.

private class ConnectedThread extends Thread {
   
private final BluetoothSocket mmSocket;
   
private final InputStream mmInStream;
   
private final OutputStream mmOutStream;
 
   
public ConnectedThread(BluetoothSocket socket) {
        mmSocket
= socket;
       
InputStream tmpIn = null;
       
OutputStream tmpOut = null;
 
       
// Get the input and output streams, using temp objects because
       
// member streams are final
       
try {
            tmpIn
= socket.getInputStream();
            tmpOut
= socket.getOutputStream();
       
} catch (IOException e) { }
 
        mmInStream
= tmpIn;
        mmOutStream
= tmpOut;
   
}
 
   
public void run() {
       
byte[] buffer = new byte[1024];  // buffer store for the stream
       
int bytes; // bytes returned from read()
 
       
// Keep listening to the InputStream until an exception occurs
       
while (true) {
           
try {
               
// Read from the InputStream
                bytes
= mmInStream.read(buffer);
               
// Send the obtained bytes to the UI activity
                mHandler
.obtainMessage(MESSAGE_READ, bytes, -1, buffer)
                       
.sendToTarget();
           
} catch (IOException e) {
               
break;
           
}
       
}
   
}
 
   
/* Call this from the main activity to send data to the remote device */
   
public void write(byte[] bytes) {
       
try {
            mmOutStream
.write(bytes);
       
} catch (IOException e) { }
   
}
 
   
/* Call this from the main activity to shutdown the connection */
   
public void cancel() {
       
try {
            mmSocket
.close();
       
} catch (IOException e) { }
   
}
}


프로파일로 동작하기

안드로이드 3.0부터 블루투스프로파일로 동작이 가능해졌다. 블루투스프로파일은 무선인터페이스 규격으로 블루투스기반의 디바이스간 통신에 기반한것이다. 예를 들어 헨즈프리프로파일같은 것이 있는데 모바일폰과 헤드셋간의 연결이 가능하려면 두 디바이스 모두 핸즈프리 프로파일을 지원해야 한다.

블루투스프로파일을 직접 커스텀하게 작성이 가능하다. 안드로이드 블루투스 API는 다음의 프로파일의 구현을 지원한다.

- 헤드셋

- A2DP

- Health Device

프로파일기반으로 동작시키려면 다음과정으로 진행한다.

1. 블루투스어댑터를 얻는다.

2. 프로파일 프록시 객체를 얻는다 getProfileProxy(). 이 객체로 연결을 달성하게 된다. 아래 예제에서는 BluetoothHeadset의 인스턴스를 프록시객체로 사용하였다.

3. BluetoothProfile.ServiceListener를 셋업하여 연결과 해재 이벤트를 처리한다.

4. onServiceConnected()에서 프록시객체의 핸들을 얻는다.

5. 프록시객체를 얻으면 이 객체를 통하여 연결상태를 모니터링하고 해당 프로파일과 연관된 동작들을 수행할 수 있다.

다음은 BluetoothHeadset 프록시객체를 사용하여 해드셋프로파일을 제어하는 예이다.

BluetoothHeadset mBluetoothHeadset;
 
// Get the default adapter
BluetoothAdapter mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
 
// Establish connection to the proxy.
mBluetoothAdapter
.getProfileProxy(context, mProfileListener, BluetoothProfile.HEADSET);
 
private BluetoothProfile.ServiceListener mProfileListener = new BluetoothProfile.ServiceListener() {
   
public void onServiceConnected(int profile, BluetoothProfile proxy) {
       
if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset
= (BluetoothHeadset) proxy;
       
}
   
}
   
public void onServiceDisconnected(int profile) {
       
if (profile == BluetoothProfile.HEADSET) {
            mBluetoothHeadset
= null;
       
}
   
}
};
 
// ... call functions on mBluetoothHeadset
 
// Close proxy connection after use.
mBluetoothAdapter
.closeProfileProxy(mBluetoothHeadset);


Posted by 삼스
iOS2013. 1. 15. 19:58


http://cafe.daum.net/iLogic/915W/20?docid=1KHkj915W2020110321201150

PDF 문서 생성, 출력, 변환

PDF 문서는 소형 프로그래밍 언어로 작성된 명령들로 해상도 독립 벡터 그래픽, 텍스트, 이미지를 저장한다. PDF 문서는 이미지와 텍스트를 여러 페이지 포함할 수 있다. PDF 는 크로스 플랫폼, 읽기 전용 문서, 해상도 독립 그래픽 드로잉에 유용하다.

모든 어플에 대해 Quartz 는 그림 13-1 처럼 어플의 드로잉 연산을 보존하는 충실도가 높은 PDF 문서를 생성한다. 결과 PDF 는 시스템의 다른 일부나 외우 업체 제품으로 특정 프린터나 웹을 위해 특정한 목적으로 최적화될 수도 있다. Quartz 에서 생성된 PDF 문서는 미리보기나 Acrobat 에서 볼 수 있다.

그림 13-1  Quartz 는 고해상도 PDF 문서를 생성한다.

Quartz 는 "디지털 종이" 로 PDF 를 사용할 뿐만 아니라 PDF 를 표시하고 생성하고, PDF 관련 작업들을 사용할 수 있는 수많은 API 함수중 일부를 포함하고 있다. 다음 내용을 다룬다.

PDF 언어와 문법을 포함한 PDF 에 대한 자세한 정보는 PDF 레퍼런스 네 번째 판인 버전 1.5 를 참고해라.

PDF 열기와 화면 출력

Quartz 는 PDF 문서를 표현하기 위해 CGPDFDocumentRef 데이터 타입을 제공한다.CGPDFDocumentCreateWithProvider 함수나 CGPDFDocumentCreateWithURL 함수를 사용하여 CGPDFDocument 객체를 생성해야 한다. CGPDFDocument 객체를 생성한 후, 그래픽 콘텍스트에 드로잉할 수 있다. 그림 13-2 는 PDFViewer 샘플 어플에서 표시된 PDF 문서를 보여준다. Xcode 도구 CD 를 인스톨할 후, 이 어플의 Xcode 프로젝트를 다음 위치에서 찾을 수 있다.

/Developer/Examples/Quartz/PDF/PDFViewer

그림 13-2  PDFViewer 샘플 어플에 의해 표시된 PDF 문서

코드 13-1 은 CGPDFDocument 객체를 생성하고 문서내의 페이지수를 얻는 방법을 보여준다.

코드 13-1  PDF 파일로부터 CGPDFDocument 객체를 생성하는 함수

CGPDFDocumentRef MyGetPDFDocumentRef (const char *filename)
{
    CFStringRef path;
    CFURLRef url;
    CGPDFDocumentRef document;
 
    path = CFStringCreateWithCString (NULL, filename,
                         kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 1
                        kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    document = CGPDFDocumentCreateWithURL (url);// 2
    CFRelease(url);
    count = CGPDFDocumentGetNumberOfPages (document);// 3
    if (count == 0) {
        printf("`%s' needs at least one page!", filename);
        return NULL;
    }
    return document;
}

코드 설명:

  1. 디스플레이할 PDF 파일의 파일명을 나타내는 CFString 객체로 부터 CFURL 객체를 생성하기 위해 코어 파운데이션 함수를 호출해야 한다.

  2. CFURL 객체로 부터 CGPDFDocument 객체를 생성한다.

  3. 다음 코드에서 문서가 최소 한 페이지를 갖고 있는지 확인하기 위해서 PDF 의 페이지 수를 얻는다.

코드 13-2는 PDF 페이지를 그래픽 콘텍스트에 드로잉하는 방법을 보여준다.

코드 13-2  PDF 페이지를 드로잉하는 함수

void MyDisplayPDFPage (CGContextRef myContext,
                    size_t pageNumber,
                    const char *filename)
{
    CGPDFDocumentRef document;
    CGPDFPageRef page;
    CGRect box;
 
    document = MyGetPDFDocumentRef (filename);// 1
    page = CGPDFDocumentGetPage (document, pageNumber);// 2
    CGContextDrawPDFPage (myContext, page);// 3
    CGPDFDocumentRelease (document);// 4
}

코드 설명:

  1. 대입한 파일이름으로 부터 CGPDFDocument 객체를 생성하기 위해 함수를 호출한다.

  2. PDF 문서로 부터 명시한 페이지 번호의 페이지를 얻는다.  

  3. CGContextDrawPDFPage 함수를 호출하여 PDF 파일로 부터 명시한 페이지를 드로잉한다. 그래픽 콘텍스트와 드로잉할 페이지를 대입해야만 한다. iPhone OS 나 Mac OS X v10.3 이후 버전에서 어플을 수행하려면, 이전의CGContextDrawPDFDocument 함수대신에 이 함수를 사용하는 것이 좋다.

  4. CGPDFDocument 객체를 해제한다.

PDF 페이지용 변환을 생성

Quartz 는 PDF 페이지의 한 상자를 대입한 사각형으로 매핑하는 affine 변환을 생성하는 CGPDFPageGetDrawingTransform함수를 제공한다. 이 함수의 형식은 다음과 같다.

CGAffineTransform CGPDFPageGetDrawingTransform (
        CGPPageRef page,
        CGPDFBox box,
        CGRect rect,
        int rotate,
        bool preserveAspectRatio
);

함수는 다음 알고리즘을 사용하여 affine 변환을 리턴한다.

  • 파라미터에 대입하는 media, crop, bleed, trim, art 와 같은 PDF 박스의 타입과 명시된 PDF 페이지의 /MediaBox 엔트리와 관련된 사각형을 교차시킨다. 교차하여 교집합 부분이 유효한 결과 사각형이 된다.

  • PDF 페이지의 /Rotate 엔트리에 의해 명시된 값에 의해서 유효 사각형을 회전시킨다.

  • 결과 사각형을 파라미터로 제공한 사각형의 중심으로 옮긴다.

  • 대입한 rotate 파라미터의 값이 0 이 아니고 90 의 배수면, 함수는 대입한 각도로 유효 사각형을 회전시킨다. 양수 값은 오른쪽으로 사각형을 회전시키며, 음수 값은 사각형을 왼쪽으로 회전시킨다. 전달하는 각도는 라디안 값이 아니다. PDF 페이지의 /Rotate 엔트리도 회전을 포함한다. 대입하는 rotate 파라미터는 /Rotate 엔트리와 조합된다.

  • 필요하면 유효 사각형을 확대/축소한다. 그래서, 대입한 사각형의 가장자리와 일치시킨다. 

  • preserveAspectRatio 파라미터에 true 를 전달하여 가로 세로의 비를 보존한다면, 마지막 사각형은 rect 파라미터에서 명시된 사각형의 제한된 가장자리와 일치시킨다.

예를 들어 그림 13-3 에서 보이는 PDF 파일을 보여주는 어플을 작성할 때 이 함수를 사용할 수 있다. 왼쪽과 오른쪽으로 회전하는 기능을 제공하고자 한다면, 현재 윈도우 크기와 회전하는 설정에 대한 적절한 변환을 계산하기 위해CGPDFPageGetDrawingTransform 를 호출할 수 있다.

그림 13-3  오른쪽으로 90 도 회전된 PDF 페이지

코드 13-3 은 함수에 전달된 파라미터를 사용하여 PDF 페이지용 affine 변환을 생성하는 함수가 변환을 적용하고 PDF 페이지를 드로잉하는 방법을 보여준다.

코드 13-3  PDF 페이지용 affine 변환 생성

void MyDrawPDFPageInRect (CGContextRef context,
                    CGPDFPageRef page,
                    CGPDFBox box,
                    CGRect rect,
                    int rotation,
                    bool preserveAspectRatio)
{
    CGAffineTransform m;
 
    m = CGPDFPageGetDrawingTransform (page, box, rect, rotation,// 1
                                    preserveAspectRato);
    CGContextSaveGState (context);// 2
    CGContextConcatCTM (context, m);// 3
    CGContextClipToRect (context,CGPDFPageGetBoxRect (page, box));// 4
    CGContextDrawPDFPage (context, page);// 5
    CGContextRestoreGState (context);// 6
}

코드 설명:

  1. 함수에 제공된 파라미터로 부터 affine 변환을 생성한다.

  2. 그래픽 상태를 저장한다.

  3. CTM 을 affine 변환과 연관시킨다.

  4. 그래픽 콘텍스트를 box 파라미터에 대입된 사각형으로 자른다. CGPDFPageGetBoxRect 함수는 대입한 상수kCGPDFMediaBoxkCGPDFCropBoxkCGPDFBleedBox,kCGPDFTrimBoxkCGPDFArtBox 과 관련된 (media, crop, bleed, trim, art box) 형 사각형을 경계로하는 페이지를 얻는다.

  5. PDF 페이지를 변환되고 잘린 콘텍스트에 드로잉한다.

  6. 그래픽 상태를 복원한다.

PDF 파일 생성

 PDF 파일을 그래픽 콘텍스트에 드로잉하는 것과 같이 Quartz 2D 를 사용하여 PDF 파일을 생성하는 것은 쉽다. PDF 파일의 위치를 명시하고, PDF 그래픽 콘텍스트를 설정하고, 다른 그래픽 콘텍스트에서 사용했던 동일한 드로잉 루틴을 사용하게 된다. 코드 13-4 의 MyCreatePDFFile 함수는 PDF 를 생성하기 위해 사용하는 모든 작업을 보여줄 것이다.

코드는 CGContextBeginPage 함수와 CGContextEndPage 함수를 호출하여 PDF 페이지를 묘사한다. iPhone OS 와 Mac OS X v10.4 이후 버전에서는, CGPDFContextBeginPage 함수와 CGPDFContextEndPage 함수를 대신 사용할 수 있다. 새로 추가된 함수들의 장점은 media, crop bleed, trim, art box 의 페이지 속성을 대입하기 위해 CFDictionary 를 전달할 수 있다는 점이다.

사전용 키 상수의 목록과 이들에 대한 정보는 CGPDFContext 레퍼런스 를 참고해라.

코드 13-4  PDF 를 생성하는 함수

void MyCreatePDFFile (CGRect pageRect, const char *filename)// 1
{
    CGContextRef pdfContext;
    CFStringRef path;
    CFURLRef url;
    CFMutableDictionaryRef myDictionary = NULL;
 
    path = CFStringCreateWithCString (NULL, filename, // 2
                                kCFStringEncodingUTF8);
    url = CFURLCreateWithFileSystemPath (NULL, path, // 3
                     kCFURLPOSIXPathStyle, 0);
    CFRelease (path);
    myDictionary = CFDictionaryCreateMutable(NULL, 0,
                        &kCFTypeDictionaryKeyCallBacks,
                        &kCFTypeDictionaryValueCallBacks); // 4
    CFDictionarySetValue(myDictionary, kCGPDFContextTitle, CFSTR("My PDF File"));
    CFDictionarySetValue(myDictionary, kCGPDFContextCreator, CFSTR("My Name"));
    pdfContext = CGPDFContextCreateWithURL (url, &pageRect, myDictionary); // 5intent 
    CFRelease(myDictionary);
    CFRelease(url);
    CGContextBeginPage (pdfContext, &pageRect); // 6
    myDrawContent (pdfContext);// 7
    CGContextEndPage (pdfContext);// 8
    CGContextRelease (pdfContext);// 9
}

코드 설명:

  1. PDF 페이지의 크기를 나타내는 사각형과 파일명을 나타내는 문자열을 파라미터로 받는다.

  2. MyCreatePDFFile 함수에 전달된 파일명으로 부터 CFString 객체를 생성한다.

  3. CFString 객체로 부터 CFURL 객체를 생성한다.

  4. 메타데이터를 얻기 위해서 빈 CFDictionary 객체를 생성한다. 다음 두 줄은 타이틀과 작가 이름을 추가하는 것이다.CFDictionarySetValue 함수를 사용하여 여러 키-값 쌍을 추가할 수 있다. 사전을 생성하는데 대한 자세한 정보는CFDictionary 레퍼런스 을 참고해라.

  5. 다음의 3 개의 파라미터를 전달하여 PDF 그래픽 콘텍스트를 생성한다.

    • PDF 데이터의 위치를 나타내는 CFURL 객체.

    • PDF 페이지의 기본 크기와 위치를 정의하는 사각형에 대한 포인터. 사각형의 원점은 일반적으로 (0, 0) 이다. Quartz 는 이 사각형을 페이지의 미디어 박스의 기본 영역으로 사용한다. NULL 을 전달하면, Quartz 는 8.5 x 11 인치(612 x 792 픽셀)의 기본 페이지 크기를 사용한다.

    • PDF 메타데이터를 포함하는 CFDictionary 객체. 추가할 메타데이터가 없다면 NULL 을 전달한다. 

      iPhone OS 와 Mac OS X v10.4 에서는 부분 형식, 조건, 조건 식별자, 레지스트리 이름, 목적 파일 프로필, 목적 장치나 제조 조건에 관한 추가 정보나 설명을 포함하는 사람이 읽ㅅ을 수 있는 문자열 등의 출력 옵션을 표시하기 위해 CFDictionary 객체를 사용할 수 있다. 출력 옵션에 대한 자세한 정보는 CGPDFContext 레퍼런스를 참고해라.

  6. 페이지의 시작을 나타낸다. PDF 와 같은 다중 페이지를 제공하는 그래픽 콘텍스트를 사용할 때, 출력에서 페이지의 경계를 나타내기 위해 CGContextEndPage 와 CGContextBeginPage 함수를 호출해야 한다. Quartz 는 페이지 기반 콘텍스트에서 페이지의 경계를 넘어가는 외부에서 실행된 모든 드로잉 연산은 무시한다. 

    iPhone OS 와 Mac OS X v10.4 이후 버전에서, 페이지의 속성을 정의하기 위해 키-값 쌍을 포함하는 그래픽 콘텍스트와 CFDictionary 를 제공하는 CGPDFContextBeginPage 함수를 대신 사용할 수 있다.

  7. PDF 콘텍스트에 콘텢츠를 드롱이하기 위해 어플에서 정의한 함수를 호출한다. 여기에 드로잉 루틴들을 작성하면 된다.

  8. 페이지 기반 그래픽 콘텍스트에 페이지가 끝났다고 알린다.

    iPhone OS 와 Mac OS X v10.4 이후 버전에서 이전에 CGPDFContextBeginPage 함수를 호출했다면, 페이지의 끝을 알리기 위해 CGPDFContextEndPage 함수를 사용해야만 했다.

  9. PDF 콘텍스트를 해제한다.

링크 추가

생성한 PDF 콘텍스트에 링크와 지점을 추가할 수 있다. iPhone OS 와 Mac OS X v10.4 부터, Quartz 는 링크에 관한 정보와 파라미터로 PDF 그래픽 콘텍스트를 갖는 다음의 3 가지 함수를 제공한다.

  • CGPDFContextSetURLForRect 는 현재 PDF 페이지에서 사각형을 클릭할 때 오픈할 URL 을 명시하도록 한다.

  • CGPDFContextSetDestinationForRect 는 현재 PDF 페이지에서 사용자가 사각형을 클릭할 때 목적지로 이동하도록 설정한다. 목적지 이름을 명시해야 한다.

  • CGPDFContextAddDestinationAtPoint 는 현재 PDF 페이지에서 점을 클릭할 때 이동할 목적지를 설정하도록 한다. 목적지 이름을 명시해야 한다.

PDF 콘텐츠 보호

iPhone OS 와 Mac OS X v10.4 부터 가능한 PDF 콘텐츠를 보호하려면, CGPDFContextCreate 함수에 전달할 보조 사전에서 명시할 수 있는 여러 보안 옵션들이 존재한다. 소유자 패스워드, 사용자 패스워드, PDF 가 보조 사전에 다음 키를 포함하여 복사될 수 있는지 프린트될 수 있는지를 설정할 수 있다. 

  • kCGPDFContextOwnerPassword 는 PDF 문서의 소유자 패스워드를 정의할 때 사용한다. 이 키가 대입되면, 문서는 소유자 패스워드를 값으로 사용하여 암호화된다. 그렇지 않으면, 문서는 암호화되지 않는다. 이 키 값은 ASCII 로 표현될 수 있는 CFString 객체가 되어야 한다. 처음 32 바이트만 패스워드로 사용된다. 이 키의 디폴트 값은 없다. 이 키의 값이 ASCII 로 표현될 수 없다면, 문서는 생성되지 않으며 생성 함수는 NULL 을 리턴한다. iPhone OS 와 Mac OS X v10.4 에서 Quartz 는 40 비트 암호화를 사용한다.

  • kCGPDFContextUserPassword 는 PDF 문서의 사용자 패스워드를 정의한다. 문서가 암호화되면, 이 키 값은 문서의 사용자 패스워드가 된다. 이 값이 명시되지 않으면 사용자 패스워드는 빈 문자열이 된다. 이 키 값은 ASCII 암호화로 표현될 수 있는 CFString 객체가 되어야 한다. 첫 번째 32 바이트만 패스워드로 사용된다. 이 키 값이 ASCII 로 표현될 수 없으면, 문서는 생성되지 않고, 생성함수는 NULL 을 리턴한다.

  • kCGPDFContextAllowsPrinting 는 문서가 사용자 패스워드로 비공개가 아닐 때 프린트할 수 있는지를 나타낸다. 이 키 값은 CFBoolean 객체가 되어야 한다. 이 키의 디폴드 값은 kCFBooleanTrue 이다.

  • kCGPDFContextAllowsCopying 는 문서가 사용자 패스워드로 비공개가 아닌 경우 복사될 수 있는지를 나타낸다. 이 키 값은 CFBoolean 객체이어야 한다. 이 키의 디폴트 값은 kCFBooleanTrue 이다.

다음 강좌의 코드 14-4 는 PDF 문서가 공개인지 비공개인지를 검사하고, 패스워드를 사용하여 문서를 오픈하는 코드를 보여줄 것이다.

 

Posted by 삼스
iOS2013. 1. 15. 17:11


출처 : http://blog.naver.com/PostView.nhn?blogId=gigar&logNo=60130114031


[AppDelegate내에서 managedObjectContext객체 생성 및 준비과정]

NSManagedObject 관리객체

코어데이터로 저장하고 불러올수 있는 객체


NSManagedObjectContext 관리객체 컨텍스트

관리객체를 담는 그릇. 관리객체 컨텍스트에 관리객체가 포함되어 있음


NSPersistentStoreCoordinator 저장소 관리자

컨텍스트 내용을 파일이나 데이터베이스에 저장하는 객체


NSEntityDescription 엔티티

데이터 베이스의 테이블 구조


NSManagedObjectModel

엔티티를 모아놓은 공간


NSPropertyDescription

엔티티를 이루는 요소. 속성, 관계, 동적인 검색프로퍼티가 있다


NSFetchRequest

관리 객체 컨텍스트에서 객체를 검색할때 조건을 기술한 객체


NSPredicate

검색 요청에서 검색조건을 기술할때 사용


NSFetchedResultsController

테이블뷰가 사용하기 쉽게 검색 결과를 관리하는 도움 클래스 


코어데이터를 이용하는 일반적인 절차


1. 관리객체 컨텍스트 생성

2. 관리객체 컨텍스트에 관리객체를 검색

3. 관리객체 컨텍스트에 객체를 추가, 수정, 삭제

4. 실행 취소, 반복 처리

5. 저장소에 저장




--------------------------------------------------------------------------------------------------

[다른 클래스 내에서 사용과정]


AppDelegate 클래스에서 생성한 managedObjectContext를 다른 클래스에서도 사용하도록 하기 위해

AppDelegate객체에 접근하여 managedObjectContext를 사용하고자 한다.


어플리케이션에서 AppDelegate 클래스는 하나만 존재하기 때문에 싱글톤으로 관리할 변수가 있을 경우 다르게 구현해도 되지만,

AppDelegate에 프로퍼티로 설정하여 가져다 쓰면 된다.

다른 클래스에서 AppDelegate에 접근하고자 하고 싶을 때에는 다음과 같이 접근 가능하다

 [[UIApplication sharedApplication] delegate];


사용하고자 하는 클래스 내에 지정한 managedObjectContext의 객체를 초기화 할때

AppDelegate의 managedObjectContext 객체를 가져와 값으로 넣도록 한다.

 -(NSManagedObjectContext*)managedObjectContext {

if (managedObjectContext == nil) {

TestAppDelegate* delegate = (TestAppDelegate*)[[UIApplication sharedApplication] delegate];

managedObjectContext = [delegate managedObjectContext];

// if

return managedObjectContext;

// managedObjectContext


이제 CoreData를 사용하여 실제적으로 데이터를 가져오고 쓰고, 지우는 과정이다.

 /*read*/


NSError* error;

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc]init];

NSEntityDescription* dataEntity = [NSEntityDescription entityForName:@"CodeData" inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:dataEntity];

NSPredicate* predicate;


CodeData* codeData = nil;


predicate = [NSPredicate predicateWithFormat:@"code_type = %@ AND code_name = %@", codeType, codeName];

[fetchRequest setPredicate:predicate];

NSArray* data_list = [self.managedObjectContext executeFetchRequest:fetchRequest error:&error];

if([data_list count] > 0){

codeData = [data_list objectAtIndex:0];

}

[fetchRequest release];


 /*write*/


NSError* error;

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc]init];

NSEntityDescription* dataEntity = [NSEntityDescription entityForName:@"CodeData"

                                              inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:dataEntity];

NSPredicate* predicate;

CodeData* codeData = (CodeData*)[NSEntityDescription insertNewObjectForEntityForName:@"CodeData" 

                                              inManagedObjectContext:self.managedObjectContext];

codeData.code_type = codeType;

codeData.code_name = [codeDic objectForKey:DATA_VALUE];

codeData.code_desc = [codeDescDic objectForKey:DATA_VALUE];

[self.managedObjectContext insertObject:codeData]; //저장


[self.managedObjectContext save:&error]; //DB 커밋

[fetchRequest release];


 /*delete*/


NSError* error;

NSFetchRequest* fetchRequest = [[NSFetchRequest alloc]init];

NSEntityDescription* dataEntity = [NSEntityDescription entityForName:@"CodeData"

                                              inManagedObjectContext:self.managedObjectContext];

[fetchRequest setEntity:dataEntity];

CodeData* codeData = (CodeData*)[NSEntityDescription insertNewObjectForEntityForName:@"CodeData" 

                                              inManagedObjectContext:self.managedObjectContext];

codeData.code_type = codeType;

codeData.code_name = [codeDic objectForKey:DATA_VALUE];

codeData.code_desc = [codeDescDic objectForKey:DATA_VALUE];


[self.managedObjectContext deleteObject:tempData];//삭제


[self.managedObjectContext save:&error]; //DB 커밋

[fetchRequest release];

[출처] CoreData 사용(수정 중)|작성자 gigar


Posted by 삼스
Windows2013. 1. 2. 15:49


MVC나 MVVC모델을 사용하여 화면과 데이터를 분리하여 개발할것을 권장한다. 좋은 메트오앱은 view model을 얼마나 잘 적용하였느냐가 관건이다.

여기서는 Data로써 GroceryItem을 정의한다. 따라서 다음과 같이 GroceryItem.cs파일을 작성한다.


name, store, quantity변수가 있고 각각 getter, setter가 정의되어 있는데 특히 setter에는 내부적으로 NotifiPropertyChanged가 호출되고 있으며 PropertyChanged라는 이벤트 핸들러를 호출하고 있다. 

여기서 중요한것이 데이터들에 observable속성을 이런식으로 부여할 수 있다는 것이다. 메트로UI의 특성중에 데이터바인딩도 아주 좋은 특징중 하나이다. observable한 속성을 준 데이터가 변경이 되면 UI에 바로 반영되도록 할수 있다.

System.ComponentModel.INotifyPropertyChanged인터페이스로 observable속성을 부여할 수 있고 이 속성이 변경될때마다  PropertyChangedEventHandler 이벤트로 화면에 표시되도록 할 수 있다. 

ViewModel클래스를 하나더 추가 하였는데 이 클래스(ViewModel.cs)는 사용자데이터와 애플리케이션의 상태정보를 포함한다.



GroceryItem의 컬렉션을 관리하는게 주임무인 클래스이다. ObservableCollection객체로 관리되고 있다. 그외에 stroeList, zipCode, 그리고 현재 선택된 아이템의 인덱스(selectedItemIndex)로 구성된다.

GroceryItem이 Observable이므로 데이터가 변경되면 자동으로 UI에도 반영되기를 기대한다. 여기서 사용한 ObservableCollection은 System.Collections.ObjectModel 네임스페이스에 해당되고 이 클래스는 기본적인 콜렉션의 특성과 리스트아이템이 추가, 삭제, 변경될때 이벤트를 발생시킨다.

ViewModel클래스는 INotifyPropertyChanged를 또한 구현하고 있는데 이는 view model에도 두가지 변수에 대해 observable속성을 주었기 때문이다. HomeZipCode와 SelectedItemIndex가 그것인데 이 정보가 변경될때도 이벤트가 발생하게 된다.

페이지를 새로 정의하여 그 페이지를 맨처음 화면에 띄우고자 한다. Page폴더에 ListPage라는 페이지를 정의할것인데 이 페이지가 처음화면에 뜨도록 하기 위해서는 App.xaml.cs에서 약간의 변경이 필요하다.


위 코드의 rootFrame.Navigate(typeof(Pages.ListPage));가 그 부분이다.


데이터관점에서 설명하기 위해 UI가 아닌 ListPage.xaml.cs의 구현코드먼저 설명하겠다.

ViewModel객체를 가지고 있으며 Store를 4가지, 그리고 GroceryList를 4가지 추가하였다. 여기서 가장 중요한 부분은 this.DataContext = viewModel; 부분이다. 메트로UI의 가장 큰 장점은 데이터바인딩을 통해 UI에 바로 적용되는 것이며 이를 위해 데이터의 소스를 지정하는 것이 중요하다 이 작업을 하는 것이 DataContext를 지정하는 것이다.

또한 List의 아이템이 변경되었을때 이벤트핸들러가 추가되어 있다. 여기서 viewModel.SelectedItemIndex에 인덱스를 업데이트한다. 이 작업은 내부적으로 observable 속성의 영향으로 PropertyChanged이벤트가 호출되면서 화면을 업데이트 하게 된다.


ListPage의 XAML코드는 다음과 같다.


Grid의 Background속성에 AppBackgroundColor라는 StandardStyle.xaml에 정의되지 않은 속성을 부여하였다. 이는 별도의 스타일을 추가로 정의하여 변경함을 의미한다. 이렇게 사용자가 원하는데로 스타일속성을 재정의하여 사용이 가능하다. 그리고 2개의 컬럼을 정의하여 화면은 두갈래로 나누었고 각 칼럼별로 row를 두개를 두어서 화면은 4분할 하였다.

좌측레이아웃은 row두개를 합쳐서 하나로 만들었다.

<StackPanel Grid.RowSpan="2"> 

이 패널은 헤더를 표시하는 TextBlock과 List뷰를 포함한다. 

우측레이아웃은 StackPanel이 두개가 준비되어있다. Grid.Column과 Grid.Row속성으로 위치를 조정할 수 있다.

디자인화면은 데이터가 동적이기 때문에 볼수 없다. ListView는 리스트내의 아이템들을 표시할것인데 다음과 같이 3가지 속성을 줌으로써 가능하다.


ItemSource속성은 어디에서 데이터들을 가져와야 하는지를 지정한다.

ItemTemplate은 ItemSource의 데이터들을 어떻게 화면에 표시할것인지를 결정한다. 이 템플릿도 별도의 스타일로 미리 지정된 스타일을 지정하는 방식으로 처리된다.

마지막으로 리스트아이템이 변경되었을 때 의 이벤트 핸들러를 추가해준다.


이제는 상세내역과 아이템이 선택되지 않았을 때 등을 표시하기 위한 페이지의 추가방법을 설명한다.

모든 컨트롤들과 코드를 하나의 파일안에 구현할 필요는 없다. 프로젝트를 관리하기 쉽게 하기 위해 여러개의 페이지를 만들고 필요에 따라 화면에 띄우면 된다. 간단한 데모로 NoItemSelected.xaml을 새로운 페이지로 프로젝트에 추가한다.


이 페이지는 Frame control을 통해서 화면에 보여질 수 있는데 위에서 ListPage.xaml의 Item Detail부분을 다음과 같이 Frame속성을 추가하여 x:Name을 지정하면 동적으로 코드레벨에서 특정 페이지를 표시할 수 있다.


<Frame x:Name="ItemDetailFrame">으로 프레임속성을 부여하였고 코드에서 ItemDetailFrame.Navigate(typeof(NoItemSelected)); 로 동적으로 페이지를 표시하였다.


동적으로 다른 페이지를 레이아웃에 집어넣어 표시되게 할 수 있다. ItemDetail.xaml을 새로운 페이지로 정의하여 데모를 보자.



페이지의 변경은 viewModel의 SelectedItemIndex가 변경될때마다 해주면 된다.

ListPage.xaml.cs의 생성자부분을 다음과 같이 수정한다.

SelectedItemIndex가 -1이 아니면 viewModel을 파라메터로 하여 ItemDetailFrame의 Page를 변경한다.

여기서 viewModel을 Navigate메서드에 인자로 넣었음을 중요하게 인지해야 한다.

이 인자는 ItemDetail page에서 OnNavigatedTo를 통해서 전달되어진다.


SetItemDetail메서드는 선택된 아이템정보를 화면에 표시하는 함수이다.

HandleItemChange메서드는 사용자가 입력한 정보를 아이템데이터에 업데이트 하는 함수이다.


Posted by 삼스
Windows2013. 1. 2. 15:23


XAML을 잘 몰라도 된다. 아주 쉽다. 안드로이드 개발자라면 안드로이드 레이아웃으로 화면 만드는것과 유사하다고 생각하면 된다.

다음은 BlankPage.xaml에 버튼두개를 배치하는 예이다.



Grid안에 StackPanel이 있고 정중앙에 배치하였다. StackPanel에는 버튼두개를 정의하였고 첫번째 버튼은 "FirstButton" 두번째 버튼은 이름없이 정의하였다. 이 이름은 이 버튼객체에 접근할때 사용된다. 버튼의 각종 속성과 스타일을 설정할 수 있다. 이 모든 작업은 VS의 design툴에서 쉽게 속성의 변경및 추가가 가능하다.

위 작업을 하면 다음과 같은 화면이 뜨게 된다.


첫번째 버튼을 우르면 호출되는 이벤트 핸들러는 이미 xaml에 정의되어 있다. Click="ButtonClick"이 해당되는데 이 이벤트를 처리하는 코드는 BlankPage.xaml.cs에 다음과 같이 추가가능하다.


위코드는 버튼의 라벨텍스트를 콘솔에 디버그문자열로 찍어준다.

런타입에 버튼객체의 속성을 변경하여 모양을 변경할 수 있다. 첫번째버튼에 x:Name="FirstButton" 으로 버튼객체의 이름을 지정하였는데 이 이름을 사용하여 바로 버튼객체의 속성이나 메소드를 호출할 수 있다.







Posted by 삼스
Windows2012. 12. 27. 13:41



Implementing a Contract


Suspending과 Resuming은 생명주기 이벤트일 뿐아니라 Contract시스템의 일부로도 사용된다. 여기서는 SearchContract의 적용예를 설명할 것이다.


먼저 manifest에 선언을 하나 해주어야 한다. package.appxmanifest를 열어서 Declaration tab으로 가면 유효한 contract list가 나올것이다. Search를 선택하고 Add버튼을 눌러라. Search constract의 속서은 변경하지 않겠다.


Search contract의 목적은 시스템의 검색기능을 애플리케이션까지 확장하기 위해서이다. 여기서는 grocery list의 아이템들 중에서 검색된 첫번째 정보를 찾아줄것이다. 이는 검색을 위해서 많은 작업을 요하지 않으며 나는 ViewModel에 검색을 위핸 메서드 SearchAndSelect를 추가할 것이다.


using System.Collections.Generic;

using System.Collections.ObjectModel;

using System.ComponentModel;

namespace MetroGrocer.Data {

  public class ViewModel : INotifyPropertyChanged {

    private ObservableCollection<GroceryItem> groceryList;

    private List<string> storeList;

    private int selectedItemIndex;

    private string homeZipCode;

    private string location;

    public ViewModel() {

      groceryList = new ObservableCollection<GroceryItem>();

      storeList = new List<string>();

      selectedItemIndex = -1;

      homeZipCode = "NY 10118";

      location = "Unknown";

}

    public void SearchAndSelect(string searchTerm) {

      int selIndex = -1;

      for (int i = 0; i < GroceryList.Count; i++) {

        if (GroceryList[i].Name.ToLower().Contains(searchTerm.ToLower())) {

          selIndex = i;

          break;

} }

      SelectedItemIndex = selIndex;

    }

// ...properties removed for brevity...
public event PropertyChangedEventHandler PropertyChanged; private void NotifyPropertyChanged(string propName) {

      if (PropertyChanged != null) {

        PropertyChanged(this, new PropertyChangedEventArgs(propName));

} }

} }

이 메서드는 사용자가 입력한 문자열을 인자로 받아 grocery list에서 찾은 후 첫번째로 매칭된 아이템의 인덱스를 선택한다. 매치가 안되면 -1이다. SelectedItemIndex가 observable이기 때문에 아이템 검색은 그 아이넴을 선택하고 그 결과 애플리케이션 레이아웃에 선택된 아이템의 정보가 표시될것이다.

이를 위해 ListPage.xaml.cs에서 선택된 아이템으로 표시되도록 일부 수정해야 한다.


protected override void OnNavigatedTo(NavigationEventArgs e) {

  viewModel = (ViewModel)e.Parameter;

  ItemDetailFrame.Navigate(typeof(NoItemSelected));

  viewModel.PropertyChanged += (sender, args) => {

    if (args.PropertyName == "SelectedItemIndex") {

  groceryList.SelectedIndex = viewModel.SelectedItemIndex;

      if (viewModel.SelectedItemIndex == -1) {

        ItemDetailFrame.Navigate(typeof(NoItemSelected));

        AppBarDoneButton.IsEnabled = false;

      } else {

        ItemDetailFrame.Navigate(typeof(ItemDetail), viewModel);

        AppBarDoneButton.IsEnabled = true;

      }

} };

...


Contract관련 생명주기

Application class의 몇몇 메서드를 override함으로써 contract에 대응되는 생명주기 이벤트를 처리할 수 있다. 다음은 OnSearchActivated 메서드의 구현예이다. 이는 사용자가 이 앱을 타겟으로 검색할때 이 메서드가 호출된다.


using System.Threading;

using System.Threading.Tasks;

using MetroGrocer.Data;

using Windows.ApplicationModel;

using Windows.ApplicationModel.Activation;

using Windows.UI.Core;

using Windows.UI.Xaml;

using Windows.UI.Xaml.Controls;

namespace MetroGrocer {

  sealed partial class App : Application {

    private ViewModel viewModel;

    private Task locationTask;

    private CancellationTokenSource locationTokenSource;

    private Frame rootFrame;

    public App() {

      this.InitializeComponent();

viewModel = new ViewModel();
// ...test data removed for brevity...

      this.Suspending += OnSuspending;

      this.Resuming += OnResuming;

      StartLocationTracking();

    }

    protected override void OnLaunched(LaunchActivatedEventArgs args) {

      // Create a Frame to act navigation context and navigate to the first page

      rootFrame = new Frame();

      rootFrame.Navigate(typeof(Pages.MainPage), viewModel);

      // Place the frame in the current Window and ensure that it is active

      Window.Current.Content = rootFrame;

      Window.Current.Activate();

}

protected override void OnSearchActivated(SearchActivatedEventArgs args) {

 viewModel.SearchAndSelect(args.QueryText);

}

//...other methods removed for brevity

} }


이것이 search contract를 지원하기 위한 작업의 전부이다. 

Posted by 삼스