parent
ce40468a9a
commit
90906fd526
@ -0,0 +1,113 @@ |
||||
# Xcode |
||||
# |
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore |
||||
|
||||
## User settings |
||||
xcuserdata/ |
||||
|
||||
## compatibility with Xcode 8 and earlier (ignoring not required starting Xcode 9) |
||||
*.xcscmblueprint |
||||
*.xccheckout |
||||
|
||||
## compatibility with Xcode 3 and earlier (ignoring not required starting Xcode 4) |
||||
build/ |
||||
DerivedData/ |
||||
*.moved-aside |
||||
*.pbxuser |
||||
!default.pbxuser |
||||
*.mode1v3 |
||||
!default.mode1v3 |
||||
*.mode2v3 |
||||
!default.mode2v3 |
||||
*.perspectivev3 |
||||
!default.perspectivev3 |
||||
|
||||
## Xcode Patch |
||||
*.xcodeproj/* |
||||
!*.xcodeproj/project.pbxproj |
||||
!*.xcodeproj/xcshareddata/ |
||||
!*.xcworkspace/contents.xcworkspacedata |
||||
/*.gcno |
||||
|
||||
# Xcode |
||||
# |
||||
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore |
||||
|
||||
## Build generated |
||||
build/ |
||||
DerivedData/ |
||||
|
||||
## Various settings |
||||
*.pbxuser |
||||
!default.pbxuser |
||||
*.mode1v3 |
||||
!default.mode1v3 |
||||
*.mode2v3 |
||||
!default.mode2v3 |
||||
*.perspectivev3 |
||||
!default.perspectivev3 |
||||
xcuserdata/ |
||||
|
||||
## Other |
||||
*.moved-aside |
||||
*.xccheckout |
||||
*.xcscmblueprint |
||||
|
||||
## Obj-C/Swift specific |
||||
*.hmap |
||||
*.ipa |
||||
*.dSYM.zip |
||||
*.dSYM |
||||
|
||||
## Playgrounds |
||||
timeline.xctimeline |
||||
playground.xcworkspace |
||||
|
||||
# Swift Package Manager |
||||
# |
||||
# Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. |
||||
# Packages/ |
||||
# Package.pins |
||||
# Package.resolved |
||||
.build/ |
||||
|
||||
# CocoaPods |
||||
# |
||||
# We recommend against adding the Pods directory to your .gitignore. However |
||||
# you should judge for yourself, the pros and cons are mentioned at: |
||||
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control |
||||
# |
||||
# Pods/ |
||||
# |
||||
# Add this line if you want to avoid checking in source code from the Xcode workspace |
||||
# *.xcworkspace |
||||
|
||||
# Carthage |
||||
# |
||||
# Add this line if you want to avoid checking in source code from Carthage dependencies. |
||||
# Carthage/Checkouts |
||||
|
||||
Carthage/Build |
||||
|
||||
# Accio dependency management |
||||
Dependencies/ |
||||
.accio/ |
||||
|
||||
# fastlane |
||||
# |
||||
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the |
||||
# screenshots whenever they are needed. |
||||
# For more information about the recommended setup visit: |
||||
# https://docs.fastlane.tools/best-practices/source-control/#source-control |
||||
|
||||
fastlane/report.xml |
||||
fastlane/Preview.html |
||||
fastlane/screenshots/**/*.png |
||||
fastlane/test_output |
||||
|
||||
# Code Injection |
||||
# |
||||
# After new code Injection tools there's a generated folder /iOSInjectionProject |
||||
# https://github.com/johnno1962/injectionforxcode |
||||
|
||||
iOSInjectionProject/ |
@ -0,0 +1,382 @@ |
||||
// !$*UTF8*$! |
||||
{ |
||||
archiveVersion = 1; |
||||
classes = { |
||||
}; |
||||
objectVersion = 50; |
||||
objects = { |
||||
|
||||
/* Begin PBXBuildFile section */ |
||||
9345B08222CEEC190075712A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9345B08122CEEC190075712A /* AppDelegate.swift */; }; |
||||
9345B08422CEEC190075712A /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 9345B08322CEEC190075712A /* ViewController.swift */; }; |
||||
9345B08722CEEC190075712A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9345B08522CEEC190075712A /* Main.storyboard */; }; |
||||
9345B08922CEEC1A0075712A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 9345B08822CEEC1A0075712A /* Assets.xcassets */; }; |
||||
9345B08C22CEEC1A0075712A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 9345B08A22CEEC1A0075712A /* LaunchScreen.storyboard */; }; |
||||
9345B09F22CEEF9F0075712A /* WebViewJavascriptBridgeBase.m in Sources */ = {isa = PBXBuildFile; fileRef = 9345B09722CEEF9F0075712A /* WebViewJavascriptBridgeBase.m */; }; |
||||
9345B0A022CEEF9F0075712A /* WKWebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9345B09822CEEF9F0075712A /* WKWebViewJavascriptBridge.m */; }; |
||||
9345B0A122CEEF9F0075712A /* WebViewJavascriptBridge.m in Sources */ = {isa = PBXBuildFile; fileRef = 9345B09922CEEF9F0075712A /* WebViewJavascriptBridge.m */; }; |
||||
9345B0A222CEEF9F0075712A /* WebViewJavascriptBridge_JS.m in Sources */ = {isa = PBXBuildFile; fileRef = 9345B09C22CEEF9F0075712A /* WebViewJavascriptBridge_JS.m */; }; |
||||
939CAD7722CF2599002D1A0C /* .gitignore in Resources */ = {isa = PBXBuildFile; fileRef = 939CAD7622CF2599002D1A0C /* .gitignore */; }; |
||||
/* End PBXBuildFile section */ |
||||
|
||||
/* Begin PBXFileReference section */ |
||||
9345B07E22CEEC190075712A /* JSBridgeIOSSwift.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = JSBridgeIOSSwift.app; sourceTree = BUILT_PRODUCTS_DIR; }; |
||||
9345B08122CEEC190075712A /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; }; |
||||
9345B08322CEEC190075712A /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = "<group>"; }; |
||||
9345B08622CEEC190075712A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; }; |
||||
9345B08822CEEC1A0075712A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; }; |
||||
9345B08B22CEEC1A0075712A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; }; |
||||
9345B08D22CEEC1A0075712A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; }; |
||||
9345B09322CEEF690075712A /* JSBridgeIOSSwift-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "JSBridgeIOSSwift-Bridging-Header.h"; sourceTree = "<group>"; }; |
||||
9345B09722CEEF9F0075712A /* WebViewJavascriptBridgeBase.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridgeBase.m; sourceTree = "<group>"; }; |
||||
9345B09822CEEF9F0075712A /* WKWebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WKWebViewJavascriptBridge.m; sourceTree = "<group>"; }; |
||||
9345B09922CEEF9F0075712A /* WebViewJavascriptBridge.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge.m; sourceTree = "<group>"; }; |
||||
9345B09A22CEEF9F0075712A /* WebViewJavascriptBridge_JS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge_JS.h; sourceTree = "<group>"; }; |
||||
9345B09B22CEEF9F0075712A /* WebViewJavascriptBridgeBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridgeBase.h; sourceTree = "<group>"; }; |
||||
9345B09C22CEEF9F0075712A /* WebViewJavascriptBridge_JS.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WebViewJavascriptBridge_JS.m; sourceTree = "<group>"; }; |
||||
9345B09D22CEEF9F0075712A /* WebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebViewJavascriptBridge.h; sourceTree = "<group>"; }; |
||||
9345B09E22CEEF9F0075712A /* WKWebViewJavascriptBridge.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WKWebViewJavascriptBridge.h; sourceTree = "<group>"; }; |
||||
939CAD7622CF2599002D1A0C /* .gitignore */ = {isa = PBXFileReference; lastKnownFileType = text; path = .gitignore; sourceTree = "<group>"; }; |
||||
/* End PBXFileReference section */ |
||||
|
||||
/* Begin PBXFrameworksBuildPhase section */ |
||||
9345B07B22CEEC190075712A /* Frameworks */ = { |
||||
isa = PBXFrameworksBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXFrameworksBuildPhase section */ |
||||
|
||||
/* Begin PBXGroup section */ |
||||
9345B07522CEEC190075712A = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
939CAD7622CF2599002D1A0C /* .gitignore */, |
||||
9345B08022CEEC190075712A /* JSBridgeIOSSwift */, |
||||
9345B07F22CEEC190075712A /* Products */, |
||||
9345B09622CEEF9F0075712A /* WebViewJavascriptBridge */, |
||||
); |
||||
sourceTree = "<group>"; |
||||
}; |
||||
9345B07F22CEEC190075712A /* Products */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
9345B07E22CEEC190075712A /* JSBridgeIOSSwift.app */, |
||||
); |
||||
name = Products; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
9345B08022CEEC190075712A /* JSBridgeIOSSwift */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
9345B08122CEEC190075712A /* AppDelegate.swift */, |
||||
9345B08322CEEC190075712A /* ViewController.swift */, |
||||
9345B08522CEEC190075712A /* Main.storyboard */, |
||||
9345B08822CEEC1A0075712A /* Assets.xcassets */, |
||||
9345B08A22CEEC1A0075712A /* LaunchScreen.storyboard */, |
||||
9345B08D22CEEC1A0075712A /* Info.plist */, |
||||
9345B09322CEEF690075712A /* JSBridgeIOSSwift-Bridging-Header.h */, |
||||
); |
||||
path = JSBridgeIOSSwift; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
9345B09622CEEF9F0075712A /* WebViewJavascriptBridge */ = { |
||||
isa = PBXGroup; |
||||
children = ( |
||||
9345B09722CEEF9F0075712A /* WebViewJavascriptBridgeBase.m */, |
||||
9345B09822CEEF9F0075712A /* WKWebViewJavascriptBridge.m */, |
||||
9345B09922CEEF9F0075712A /* WebViewJavascriptBridge.m */, |
||||
9345B09A22CEEF9F0075712A /* WebViewJavascriptBridge_JS.h */, |
||||
9345B09B22CEEF9F0075712A /* WebViewJavascriptBridgeBase.h */, |
||||
9345B09C22CEEF9F0075712A /* WebViewJavascriptBridge_JS.m */, |
||||
9345B09D22CEEF9F0075712A /* WebViewJavascriptBridge.h */, |
||||
9345B09E22CEEF9F0075712A /* WKWebViewJavascriptBridge.h */, |
||||
); |
||||
path = WebViewJavascriptBridge; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXGroup section */ |
||||
|
||||
/* Begin PBXNativeTarget section */ |
||||
9345B07D22CEEC190075712A /* JSBridgeIOSSwift */ = { |
||||
isa = PBXNativeTarget; |
||||
buildConfigurationList = 9345B09022CEEC1A0075712A /* Build configuration list for PBXNativeTarget "JSBridgeIOSSwift" */; |
||||
buildPhases = ( |
||||
9345B07A22CEEC190075712A /* Sources */, |
||||
9345B07B22CEEC190075712A /* Frameworks */, |
||||
9345B07C22CEEC190075712A /* Resources */, |
||||
); |
||||
buildRules = ( |
||||
); |
||||
dependencies = ( |
||||
); |
||||
name = JSBridgeIOSSwift; |
||||
productName = JSBridgeIOSSwift; |
||||
productReference = 9345B07E22CEEC190075712A /* JSBridgeIOSSwift.app */; |
||||
productType = "com.apple.product-type.application"; |
||||
}; |
||||
/* End PBXNativeTarget section */ |
||||
|
||||
/* Begin PBXProject section */ |
||||
9345B07622CEEC190075712A /* Project object */ = { |
||||
isa = PBXProject; |
||||
attributes = { |
||||
LastSwiftUpdateCheck = 1020; |
||||
LastUpgradeCheck = 1020; |
||||
TargetAttributes = { |
||||
9345B07D22CEEC190075712A = { |
||||
CreatedOnToolsVersion = 10.2.1; |
||||
LastSwiftMigration = 1020; |
||||
}; |
||||
}; |
||||
}; |
||||
buildConfigurationList = 9345B07922CEEC190075712A /* Build configuration list for PBXProject "JSBridgeIOSSwift" */; |
||||
compatibilityVersion = "Xcode 9.3"; |
||||
developmentRegion = en; |
||||
hasScannedForEncodings = 0; |
||||
knownRegions = ( |
||||
en, |
||||
Base, |
||||
); |
||||
mainGroup = 9345B07522CEEC190075712A; |
||||
productRefGroup = 9345B07F22CEEC190075712A /* Products */; |
||||
projectDirPath = ""; |
||||
projectRoot = ""; |
||||
targets = ( |
||||
9345B07D22CEEC190075712A /* JSBridgeIOSSwift */, |
||||
); |
||||
}; |
||||
/* End PBXProject section */ |
||||
|
||||
/* Begin PBXResourcesBuildPhase section */ |
||||
9345B07C22CEEC190075712A /* Resources */ = { |
||||
isa = PBXResourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
939CAD7722CF2599002D1A0C /* .gitignore in Resources */, |
||||
9345B08C22CEEC1A0075712A /* LaunchScreen.storyboard in Resources */, |
||||
9345B08922CEEC1A0075712A /* Assets.xcassets in Resources */, |
||||
9345B08722CEEC190075712A /* Main.storyboard in Resources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXResourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXSourcesBuildPhase section */ |
||||
9345B07A22CEEC190075712A /* Sources */ = { |
||||
isa = PBXSourcesBuildPhase; |
||||
buildActionMask = 2147483647; |
||||
files = ( |
||||
9345B08422CEEC190075712A /* ViewController.swift in Sources */, |
||||
9345B0A022CEEF9F0075712A /* WKWebViewJavascriptBridge.m in Sources */, |
||||
9345B0A222CEEF9F0075712A /* WebViewJavascriptBridge_JS.m in Sources */, |
||||
9345B09F22CEEF9F0075712A /* WebViewJavascriptBridgeBase.m in Sources */, |
||||
9345B08222CEEC190075712A /* AppDelegate.swift in Sources */, |
||||
9345B0A122CEEF9F0075712A /* WebViewJavascriptBridge.m in Sources */, |
||||
); |
||||
runOnlyForDeploymentPostprocessing = 0; |
||||
}; |
||||
/* End PBXSourcesBuildPhase section */ |
||||
|
||||
/* Begin PBXVariantGroup section */ |
||||
9345B08522CEEC190075712A /* Main.storyboard */ = { |
||||
isa = PBXVariantGroup; |
||||
children = ( |
||||
9345B08622CEEC190075712A /* Base */, |
||||
); |
||||
name = Main.storyboard; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
9345B08A22CEEC1A0075712A /* LaunchScreen.storyboard */ = { |
||||
isa = PBXVariantGroup; |
||||
children = ( |
||||
9345B08B22CEEC1A0075712A /* Base */, |
||||
); |
||||
name = LaunchScreen.storyboard; |
||||
sourceTree = "<group>"; |
||||
}; |
||||
/* End PBXVariantGroup section */ |
||||
|
||||
/* Begin XCBuildConfiguration section */ |
||||
9345B08E22CEEC1A0075712A /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_ENABLE_OBJC_WEAK = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "iPhone Developer"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = dwarf; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
ENABLE_TESTABILITY = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_DYNAMIC_NO_PIC = NO; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_OPTIMIZATION_LEVEL = 0; |
||||
GCC_PREPROCESSOR_DEFINITIONS = ( |
||||
"DEBUG=1", |
||||
"$(inherited)", |
||||
); |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2; |
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; |
||||
MTL_FAST_MATH = YES; |
||||
ONLY_ACTIVE_ARCH = YES; |
||||
SDKROOT = iphoneos; |
||||
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; |
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
9345B08F22CEEC1A0075712A /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ALWAYS_SEARCH_USER_PATHS = NO; |
||||
CLANG_ANALYZER_NONNULL = YES; |
||||
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; |
||||
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14"; |
||||
CLANG_CXX_LIBRARY = "libc++"; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CLANG_ENABLE_OBJC_ARC = YES; |
||||
CLANG_ENABLE_OBJC_WEAK = YES; |
||||
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; |
||||
CLANG_WARN_BOOL_CONVERSION = YES; |
||||
CLANG_WARN_COMMA = YES; |
||||
CLANG_WARN_CONSTANT_CONVERSION = YES; |
||||
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; |
||||
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; |
||||
CLANG_WARN_DOCUMENTATION_COMMENTS = YES; |
||||
CLANG_WARN_EMPTY_BODY = YES; |
||||
CLANG_WARN_ENUM_CONVERSION = YES; |
||||
CLANG_WARN_INFINITE_RECURSION = YES; |
||||
CLANG_WARN_INT_CONVERSION = YES; |
||||
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; |
||||
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; |
||||
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; |
||||
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; |
||||
CLANG_WARN_STRICT_PROTOTYPES = YES; |
||||
CLANG_WARN_SUSPICIOUS_MOVE = YES; |
||||
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; |
||||
CLANG_WARN_UNREACHABLE_CODE = YES; |
||||
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; |
||||
CODE_SIGN_IDENTITY = "iPhone Developer"; |
||||
COPY_PHASE_STRIP = NO; |
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; |
||||
ENABLE_NS_ASSERTIONS = NO; |
||||
ENABLE_STRICT_OBJC_MSGSEND = YES; |
||||
GCC_C_LANGUAGE_STANDARD = gnu11; |
||||
GCC_NO_COMMON_BLOCKS = YES; |
||||
GCC_WARN_64_TO_32_BIT_CONVERSION = YES; |
||||
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; |
||||
GCC_WARN_UNDECLARED_SELECTOR = YES; |
||||
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; |
||||
GCC_WARN_UNUSED_FUNCTION = YES; |
||||
GCC_WARN_UNUSED_VARIABLE = YES; |
||||
IPHONEOS_DEPLOYMENT_TARGET = 12.2; |
||||
MTL_ENABLE_DEBUG_INFO = NO; |
||||
MTL_FAST_MATH = YES; |
||||
SDKROOT = iphoneos; |
||||
SWIFT_COMPILATION_MODE = wholemodule; |
||||
SWIFT_OPTIMIZATION_LEVEL = "-O"; |
||||
VALIDATE_PRODUCT = YES; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
9345B09122CEEC1A0075712A /* Debug */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CODE_SIGN_STYLE = Automatic; |
||||
INFOPLIST_FILE = JSBridgeIOSSwift/Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = ( |
||||
"$(inherited)", |
||||
"@executable_path/Frameworks", |
||||
); |
||||
PRODUCT_BUNDLE_IDENTIFIER = com.beichen.JSBridgeIOSSwift; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
SWIFT_OBJC_BRIDGING_HEADER = "JSBridgeIOSSwift/JSBridgeIOSSwift-Bridging-Header.h"; |
||||
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; |
||||
SWIFT_VERSION = 5.0; |
||||
TARGETED_DEVICE_FAMILY = "1,2"; |
||||
}; |
||||
name = Debug; |
||||
}; |
||||
9345B09222CEEC1A0075712A /* Release */ = { |
||||
isa = XCBuildConfiguration; |
||||
buildSettings = { |
||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; |
||||
CLANG_ENABLE_MODULES = YES; |
||||
CODE_SIGN_STYLE = Automatic; |
||||
INFOPLIST_FILE = JSBridgeIOSSwift/Info.plist; |
||||
LD_RUNPATH_SEARCH_PATHS = ( |
||||
"$(inherited)", |
||||
"@executable_path/Frameworks", |
||||
); |
||||
PRODUCT_BUNDLE_IDENTIFIER = com.beichen.JSBridgeIOSSwift; |
||||
PRODUCT_NAME = "$(TARGET_NAME)"; |
||||
SWIFT_OBJC_BRIDGING_HEADER = "JSBridgeIOSSwift/JSBridgeIOSSwift-Bridging-Header.h"; |
||||
SWIFT_VERSION = 5.0; |
||||
TARGETED_DEVICE_FAMILY = "1,2"; |
||||
}; |
||||
name = Release; |
||||
}; |
||||
/* End XCBuildConfiguration section */ |
||||
|
||||
/* Begin XCConfigurationList section */ |
||||
9345B07922CEEC190075712A /* Build configuration list for PBXProject "JSBridgeIOSSwift" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
9345B08E22CEEC1A0075712A /* Debug */, |
||||
9345B08F22CEEC1A0075712A /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
9345B09022CEEC1A0075712A /* Build configuration list for PBXNativeTarget "JSBridgeIOSSwift" */ = { |
||||
isa = XCConfigurationList; |
||||
buildConfigurations = ( |
||||
9345B09122CEEC1A0075712A /* Debug */, |
||||
9345B09222CEEC1A0075712A /* Release */, |
||||
); |
||||
defaultConfigurationIsVisible = 0; |
||||
defaultConfigurationName = Release; |
||||
}; |
||||
/* End XCConfigurationList section */ |
||||
}; |
||||
rootObject = 9345B07622CEEC190075712A /* Project object */; |
||||
} |
@ -0,0 +1,52 @@ |
||||
// |
||||
// AppDelegate.swift |
||||
// JSBridgeIOSSwift |
||||
// |
||||
// Created by BeiChen. |
||||
// |
||||
|
||||
import UIKit |
||||
|
||||
@UIApplicationMain |
||||
class AppDelegate: UIResponder, UIApplicationDelegate { |
||||
|
||||
var window: UIWindow? |
||||
|
||||
|
||||
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { |
||||
// Override point for customization after application launch. |
||||
return true |
||||
} |
||||
|
||||
func applicationWillResignActive(_ application: UIApplication) { |
||||
// Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. |
||||
// Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. |
||||
} |
||||
|
||||
func applicationDidEnterBackground(_ application: UIApplication) { |
||||
// Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. |
||||
// If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. |
||||
} |
||||
|
||||
func applicationWillEnterForeground(_ application: UIApplication) { |
||||
// Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. |
||||
// 当应用重新被前台调用时会走到这个生命周期方法,所以在这里进行 webView 的刷新 |
||||
if (window?.rootViewController is ViewController) { |
||||
let controller = (window?.rootViewController) as? ViewController |
||||
if controller?.webView != nil { |
||||
controller?.webView?.reload() |
||||
} |
||||
} |
||||
} |
||||
|
||||
func applicationDidBecomeActive(_ application: UIApplication) { |
||||
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. |
||||
} |
||||
|
||||
func applicationWillTerminate(_ application: UIApplication) { |
||||
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. |
||||
} |
||||
|
||||
|
||||
} |
||||
|
@ -0,0 +1,98 @@ |
||||
{ |
||||
"images" : [ |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "20x20", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "20x20", |
||||
"scale" : "3x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "29x29", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "29x29", |
||||
"scale" : "3x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "40x40", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "40x40", |
||||
"scale" : "3x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "60x60", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "iphone", |
||||
"size" : "60x60", |
||||
"scale" : "3x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "20x20", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "20x20", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "29x29", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "29x29", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "40x40", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "40x40", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "76x76", |
||||
"scale" : "1x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "76x76", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "ipad", |
||||
"size" : "83.5x83.5", |
||||
"scale" : "2x" |
||||
}, |
||||
{ |
||||
"idiom" : "ios-marketing", |
||||
"size" : "1024x1024", |
||||
"scale" : "1x" |
||||
} |
||||
], |
||||
"info" : { |
||||
"version" : 1, |
||||
"author" : "xcode" |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
{ |
||||
"info" : { |
||||
"version" : 1, |
||||
"author" : "xcode" |
||||
} |
||||
} |
@ -0,0 +1,25 @@ |
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?> |
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM"> |
||||
<dependencies> |
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13104.12"/> |
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> |
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
||||
</dependencies> |
||||
<scenes> |
||||
<!--View Controller--> |
||||
<scene sceneID="EHf-IW-A2E"> |
||||
<objects> |
||||
<viewController id="01J-lp-oVM" sceneMemberID="viewController"> |
||||
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3"> |
||||
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> |
||||
</view> |
||||
</viewController> |
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
<point key="canvasLocation" x="53" y="375"/> |
||||
</scene> |
||||
</scenes> |
||||
</document> |
@ -0,0 +1,125 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r"> |
||||
<device id="retina6_1" orientation="portrait"> |
||||
<adaptation id="fullscreen"/> |
||||
</device> |
||||
<dependencies> |
||||
<deployment identifier="iOS"/> |
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/> |
||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> |
||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> |
||||
</dependencies> |
||||
<scenes> |
||||
<!--View Controller--> |
||||
<scene sceneID="tne-QT-ifu"> |
||||
<objects> |
||||
<viewController id="BYZ-38-t0r" customClass="ViewController" customModule="JSBridgeIOSSwift" customModuleProvider="target" sceneMemberID="viewController"> |
||||
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC"> |
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
||||
<subviews> |
||||
<containerView opaque="NO" contentMode="scaleToFill" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="fOM-0y-V3i"> |
||||
<rect key="frame" x="0.0" y="440" width="414" height="456"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/> |
||||
<connections> |
||||
<segue destination="hhl-X1-HLq" kind="embed" id="ej7-M0-bJ9"/> |
||||
</connections> |
||||
</containerView> |
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="原生 IOS 界面:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="h6K-lK-jdd"> |
||||
<rect key="frame" x="20" y="454" width="123" height="42"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> |
||||
<nil key="textColor"/> |
||||
<nil key="highlightedColor"/> |
||||
</label> |
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="User 值:" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="eES-ci-BSB"> |
||||
<rect key="frame" x="28" y="533" width="76" height="32"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<fontDescription key="fontDescription" type="system" pointSize="15"/> |
||||
<nil key="textColor"/> |
||||
<nil key="highlightedColor"/> |
||||
</label> |
||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" text="" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="1u7-u1-fNB"> |
||||
<rect key="frame" x="138" y="533" width="200" height="32"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> |
||||
<nil key="textColor"/> |
||||
<nil key="highlightedColor"/> |
||||
</label> |
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="1gR-9P-tJE"> |
||||
<rect key="frame" x="20" y="597" width="151" height="30"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<state key="normal" title="修改 H5 界面 name 值"/> |
||||
<connections> |
||||
<action selector="onChangeNameBtnClick:forEvent:" destination="BYZ-38-t0r" eventType="touchDown" id="wWv-SQ-EXJ"/> |
||||
</connections> |
||||
</button> |
||||
<textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="请输入新的 name 值" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="94e-5K-FHs"> |
||||
<rect key="frame" x="218" y="597" width="176" height="30"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<nil key="textColor"/> |
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/> |
||||
<textInputTraits key="textInputTraits"/> |
||||
</textField> |
||||
<textField opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="left" contentVerticalAlignment="center" borderStyle="roundedRect" placeholder="请输入新的 token 值" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="pRP-xr-mQw"> |
||||
<rect key="frame" x="218" y="654" width="176" height="30"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<nil key="textColor"/> |
||||
<fontDescription key="fontDescription" type="system" pointSize="14"/> |
||||
<textInputTraits key="textInputTraits"/> |
||||
<attributedString key="userComments"> |
||||
<fragment content="请输入新的 token 值"/> |
||||
</attributedString> |
||||
</textField> |
||||
<button opaque="NO" contentMode="scaleToFill" fixedFrame="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="wCt-J5-5Cb"> |
||||
<rect key="frame" x="8" y="654" width="175" height="30"/> |
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> |
||||
<state key="normal" title="设置 Cookie token 值"/> |
||||
<connections> |
||||
<action selector="onCookieBtnClick:forEvent:" destination="BYZ-38-t0r" eventType="touchDown" id="8zX-6e-wGz"/> |
||||
</connections> |
||||
</button> |
||||
</subviews> |
||||
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> |
||||
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/> |
||||
</view> |
||||
<connections> |
||||
<outlet property="cookieText" destination="pRP-xr-mQw" id="2Ur-9p-8YO"/> |
||||
<outlet property="nameText" destination="94e-5K-FHs" id="ubY-Ft-go5"/> |
||||
<outlet property="userLabel" destination="1u7-u1-fNB" id="xrS-7g-yXq"/> |
||||
</connections> |
||||
</viewController> |
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="dkx-z0-nzr" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
<point key="canvasLocation" x="34.782608695652179" y="18.75"/> |
||||
</scene> |
||||
<!--View Controller--> |
||||
<scene sceneID="KbO-Gw-EOo"> |
||||
<objects> |
||||
<viewController id="UIb-mE-txe" sceneMemberID="viewController"> |
||||
<view key="view" contentMode="scaleToFill" id="yef-Bt-fvp"> |
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
||||
<viewLayoutGuide key="safeArea" id="KQp-Jg-fhP"/> |
||||
</view> |
||||
</viewController> |
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="0de-K8-zoW" userLabel="First Responder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
</scene> |
||||
<!--View Controller--> |
||||
<scene sceneID="Pr8-V0-dIy"> |
||||
<objects> |
||||
<viewController id="hhl-X1-HLq" sceneMemberID="viewController"> |
||||
<view key="view" contentMode="scaleToFill" id="O4z-r0-0qf"> |
||||
<rect key="frame" x="0.0" y="0.0" width="414" height="456"/> |
||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> |
||||
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
||||
<viewLayoutGuide key="safeArea" id="S8o-sO-0c4"/> |
||||
</view> |
||||
</viewController> |
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="ANe-kx-hCP" userLabel="First Responder" sceneMemberID="firstResponder"/> |
||||
</objects> |
||||
</scene> |
||||
</scenes> |
||||
</document> |
@ -0,0 +1,45 @@ |
||||
<?xml version="1.0" encoding="UTF-8"?> |
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> |
||||
<plist version="1.0"> |
||||
<dict> |
||||
<key>CFBundleDevelopmentRegion</key> |
||||
<string>$(DEVELOPMENT_LANGUAGE)</string> |
||||
<key>CFBundleExecutable</key> |
||||
<string>$(EXECUTABLE_NAME)</string> |
||||
<key>CFBundleIdentifier</key> |
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string> |
||||
<key>CFBundleInfoDictionaryVersion</key> |
||||
<string>6.0</string> |
||||
<key>CFBundleName</key> |
||||
<string>$(PRODUCT_NAME)</string> |
||||
<key>CFBundlePackageType</key> |
||||
<string>APPL</string> |
||||
<key>CFBundleShortVersionString</key> |
||||
<string>1.0</string> |
||||
<key>CFBundleVersion</key> |
||||
<string>1</string> |
||||
<key>LSRequiresIPhoneOS</key> |
||||
<true/> |
||||
<key>UILaunchStoryboardName</key> |
||||
<string>LaunchScreen</string> |
||||
<key>UIMainStoryboardFile</key> |
||||
<string>Main</string> |
||||
<key>UIRequiredDeviceCapabilities</key> |
||||
<array> |
||||
<string>armv7</string> |
||||
</array> |
||||
<key>UISupportedInterfaceOrientations</key> |
||||
<array> |
||||
<string>UIInterfaceOrientationPortrait</string> |
||||
<string>UIInterfaceOrientationLandscapeLeft</string> |
||||
<string>UIInterfaceOrientationLandscapeRight</string> |
||||
</array> |
||||
<key>UISupportedInterfaceOrientations~ipad</key> |
||||
<array> |
||||
<string>UIInterfaceOrientationPortrait</string> |
||||
<string>UIInterfaceOrientationPortraitUpsideDown</string> |
||||
<string>UIInterfaceOrientationLandscapeLeft</string> |
||||
<string>UIInterfaceOrientationLandscapeRight</string> |
||||
</array> |
||||
</dict> |
||||
</plist> |
@ -0,0 +1,5 @@ |
||||
//
|
||||
// Use this file to import your target's public headers that you would like to expose to Swift.
|
||||
//
|
||||
|
||||
#import "WebViewJavascriptBridge.h" |
@ -0,0 +1,231 @@ |
||||
// |
||||
// ViewController.swift |
||||
// JSBridgeIOSSwift |
||||
// |
||||
// Created by BeiChen. |
||||
// |
||||
|
||||
import UIKit |
||||
import WebKit |
||||
|
||||
/** |
||||
* 注意事项: |
||||
* 一、Webview 初始化时设置 cookie 方式: |
||||
* 1.WebViewJavascriptBridge 必须是一个全局对象,不然的话界面不显示了 |
||||
* 2.将app中设置的cookie同步到js的话,使用下面这段代码 |
||||
* let userContentController = WKUserContentController() |
||||
* let cookie = defaults["cookie"] as? String |
||||
* if !ViewController.judgeIsEmpty(with: cookie) { |
||||
* let cookieValue = "document.cookie = '\(cookie ?? "")\("';")" |
||||
* let cookieScript = WKUserScript(source: cookieValue, injectionTime: .atDocumentStart, forMainFrameOnly: false) |
||||
* userContentController.addUserScript(cookieScript) |
||||
* } |
||||
* webConfig.userContentController = userContentController |
||||
* |
||||
* 二、Webview 已经存在时设置 cookie 的方式 |
||||
* let cookieValue = "document.cookie = '\(cookie)\("';")" |
||||
* webView.evaluateJavaScript(cookieValue, completionHandler: { result, error in |
||||
* if let result = result { |
||||
* print("cookie-------\(result)") |
||||
* } |
||||
* }) |
||||
* |
||||
*/ |
||||
|
||||
//尺寸设置 |
||||
let aiScreenWidth = UIScreen.main.bounds.size.width |
||||
let aiScreenHeight = UIScreen.main.bounds.size.height |
||||
let STATUS_BAR_HEIGHT = UIApplication.shared.statusBarFrame.size.height |
||||
|
||||
class ViewController: UIViewController, WKNavigationDelegate, WKUIDelegate { |
||||
|
||||
var webView: WKWebView! |
||||
var bridge: WebViewJavascriptBridge! |
||||
var webConfig: WKWebViewConfiguration! |
||||
|
||||
@IBOutlet var nameText: UITextField! |
||||
@IBOutlet var cookieText: UITextField! |
||||
@IBOutlet var userLabel: UILabel! |
||||
|
||||
override func viewDidLoad() { |
||||
super.viewDidLoad() |
||||
|
||||
// 初始化 WKWebViewConfiguration 对象 |
||||
webConfig = WKWebViewConfiguration() |
||||
|
||||
// 设置 webConfig 属性 |
||||
setWebConfig() |
||||
|
||||
// 初始化 WKWebView |
||||
initWebView() |
||||
|
||||
// 注册与 H5 交互的事件函数 |
||||
registerHandlers() |
||||
|
||||
} |
||||
|
||||
override func viewWillAppear(_ animated: Bool) { |
||||
super.viewWillAppear(animated) |
||||
automaticallyAdjustsScrollViewInsets = false |
||||
} |
||||
|
||||
/** |
||||
* 设置 webConfig 属性 |
||||
*/ |
||||
func setWebConfig() { |
||||
|
||||
// 设置偏好设置 |
||||
webConfig.preferences = WKPreferences() |
||||
// 默认为0 |
||||
webConfig.preferences.minimumFontSize = 10 |
||||
// 默认认为YES |
||||
webConfig.preferences.javaScriptEnabled = true |
||||
// 在iOS上默认为NO,表示不能自动通过窗口打开 |
||||
webConfig.preferences.javaScriptCanOpenWindowsAutomatically = false |
||||
} |
||||
|
||||
/** |
||||
* 初始化 WKWebView |
||||
*/ |
||||
func initWebView() { |
||||
// URL 网络请求地址 |
||||
// TODO: 请替换成页面的 url 地址 |
||||
let URLSTR = "http://xxx.xxx.xxx.xxx:xxxx" |
||||
webView = WKWebView(frame: CGRect(x: 0, y: 0, width: view.bounds.size.width, height: 420), configuration: webConfig!) |
||||
// 设置 UserAgent 后缀,这里设置为 ios 用于在 H5 端进行区分 IOS 平台还是 Android 平台 |
||||
webView.customUserAgent = String(format: webView!.customUserAgent!, "ios") |
||||
webView.uiDelegate = self |
||||
webView.navigationDelegate = self |
||||
let url = URL(string: URLSTR) |
||||
var urlRequest: URLRequest? = nil |
||||
if let url = url { |
||||
urlRequest = URLRequest(url: url) |
||||
} |
||||
if let urlRequest = urlRequest { |
||||
webView.load(urlRequest) |
||||
} |
||||
view.addSubview(webView) |
||||
} |
||||
|
||||
/** |
||||
* 使用 WebViewJavascriptBridge 注册与 H5 交互的事件函数 |
||||
*/ |
||||
func registerHandlers() { |
||||
// 启用 WebViewJavascriptBridge |
||||
WebViewJavascriptBridge.enableLogging() |
||||
|
||||
// 初始化 WebViewJavascriptBridge |
||||
bridge = WebViewJavascriptBridge(forWebView: webView!); |
||||
bridge.setWebViewDelegate(self); |
||||
|
||||
// 注册刷新页面的 reloadUrl 函数 |
||||
bridge.registerHandler("reloadUrl", handler: { data, responseCallback in |
||||
self.webView?.reload() |
||||
ViewController.addToast(with: "刷新成功~", in: self.view) |
||||
responseCallback?("") |
||||
}) |
||||
|
||||
// 注册修改 User 名称的 changeUser 函数 |
||||
bridge.registerHandler("changeUser", handler: { data, responseCallback in |
||||
self.userLabel.text = data as? String |
||||
responseCallback?("") |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* 修改 name 按钮被点击时触发 |
||||
*/ |
||||
@IBAction func onChangeNameBtnClick(_ sender: UIButton, forEvent event: UIEvent) { |
||||
let name = nameText.text |
||||
// 调用 H5 界面的 changeName 事件函数 |
||||
bridge.callHandler("changeName", data: name, responseCallback: { responseData in |
||||
ViewController.addToast(with: "name 修改成功", in: self.view) |
||||
self.nameText.text = "" |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* 设置 Cookie 按钮被点击时触发 |
||||
*/ |
||||
@IBAction func onCookieBtnClick(_ sender: UIButton, forEvent event: UIEvent) { |
||||
let cookie = "token=\(cookieText.text ?? "")" |
||||
syncCookie(cookie) |
||||
// 调用 H5 界面的 syncCookie 事件函数 |
||||
bridge.callHandler("syncCookie", data: "", responseCallback: { responseData in |
||||
ViewController.addToast(with: "Cookie 同步成功", in: self.view) |
||||
self.cookieText.text = "" |
||||
}) |
||||
} |
||||
|
||||
|
||||
/** |
||||
* 用来t设置并同步 Cookie 的工具函数 |
||||
*/ |
||||
func syncCookie(_ cookie: String?) { |
||||
// 使用 WKUserScript 携带 cookie 参数传递到 js 页面 |
||||
let cookieValue = "document.cookie = '\(cookie ?? "")\("';")" |
||||
webView.evaluateJavaScript(cookieValue, completionHandler: { result, error in |
||||
if let result = result { |
||||
print("cookie-------\(result)") |
||||
} |
||||
}) |
||||
} |
||||
|
||||
/** |
||||
* 判断字符串是否为空或者 null 的方法 |
||||
*/ |
||||
class func judgeIsEmpty(with string: String?) -> Bool { |
||||
if (string?.count ?? 0) == 0 || (string == "") || string == nil || string == nil || string?.isEqual(NSNull()) ?? false { |
||||
return true |
||||
} |
||||
return false |
||||
} |
||||
|
||||
/** |
||||
* 模拟 Toast效果 的工具方法 |
||||
*/ |
||||
class func addToast(with string: String?, in view: UIView?) { |
||||
|
||||
let initRect = CGRect(x: 0, y: STATUS_BAR_HEIGHT, width: aiScreenWidth, height: 0) |
||||
let rect = CGRect(x: 0, y: STATUS_BAR_HEIGHT, width: aiScreenWidth, height: 22) |
||||
let label = UILabel(frame: initRect) |
||||
label.text = string |
||||
label.textAlignment = .center |
||||
label.textColor = UIColor.white |
||||
label.font = UIFont.systemFont(ofSize: 14) |
||||
label.backgroundColor = UIColor(red: 0, green: 0.6, blue: 0.9, alpha: 0.6) |
||||
|
||||
view?.addSubview(label) |
||||
|
||||
//弹出label |
||||
UIView.animate(withDuration: 0.5, animations: { |
||||
|
||||
label.frame = rect |
||||
}) { finished in |
||||
//弹出后持续1s |
||||
Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(removeToast(withView:)), userInfo: label, repeats: false) |
||||
} |
||||
} |
||||
|
||||
/** |
||||
* 移除 Toast |
||||
*/ |
||||
@objc class func removeToast(withView timer: Timer?) { |
||||
|
||||
let label = timer?.userInfo as? UILabel |
||||
|
||||
let initRect = CGRect(x: 0, y: STATUS_BAR_HEIGHT, width: aiScreenWidth, height: 0) |
||||
// label消失 |
||||
UIView.animate(withDuration: 0.5, animations: { |
||||
|
||||
label?.frame = initRect |
||||
}) { finished in |
||||
|
||||
label?.removeFromSuperview() |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
|
||||
|
@ -0,0 +1,34 @@ |
||||
//
|
||||
// WKWebViewJavascriptBridge.h
|
||||
//
|
||||
// Created by @LokiMeyburg on 10/15/14.
|
||||
// Copyright (c) 2014 @LokiMeyburg. All rights reserved.
|
||||
//
|
||||
|
||||
#if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) |
||||
#define supportsWKWebView |
||||
#endif |
||||
|
||||
#if defined supportsWKWebView |
||||
|
||||
#import <Foundation/Foundation.h> |
||||
#import "WebViewJavascriptBridgeBase.h" |
||||
#import <WebKit/WebKit.h> |
||||
|
||||
@interface WKWebViewJavascriptBridge : NSObject<WKNavigationDelegate, WebViewJavascriptBridgeBaseDelegate> |
||||
|
||||
+ (instancetype)bridgeForWebView:(WKWebView*)webView; |
||||
+ (void)enableLogging; |
||||
|
||||
- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; |
||||
- (void)removeHandler:(NSString*)handlerName; |
||||
- (void)callHandler:(NSString*)handlerName; |
||||
- (void)callHandler:(NSString*)handlerName data:(id)data; |
||||
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; |
||||
- (void)reset; |
||||
- (void)setWebViewDelegate:(id)webViewDelegate; |
||||
- (void)disableJavscriptAlertBoxSafetyTimeout; |
||||
|
||||
@end |
||||
|
||||
#endif |
@ -0,0 +1,198 @@ |
||||
// |
||||
// WKWebViewJavascriptBridge.m |
||||
// |
||||
// Created by @LokiMeyburg on 10/15/14. |
||||
// Copyright (c) 2014 @LokiMeyburg. All rights reserved. |
||||
// |
||||
|
||||
|
||||
#import "WKWebViewJavascriptBridge.h" |
||||
|
||||
#if defined supportsWKWebView |
||||
|
||||
@implementation WKWebViewJavascriptBridge { |
||||
__weak WKWebView* _webView; |
||||
__weak id<WKNavigationDelegate> _webViewDelegate; |
||||
long _uniqueId; |
||||
WebViewJavascriptBridgeBase *_base; |
||||
} |
||||
|
||||
/* API |
||||
*****/ |
||||
|
||||
+ (void)enableLogging { [WebViewJavascriptBridgeBase enableLogging]; } |
||||
|
||||
+ (instancetype)bridgeForWebView:(WKWebView*)webView { |
||||
WKWebViewJavascriptBridge* bridge = [[self alloc] init]; |
||||
[bridge _setupInstance:webView]; |
||||
[bridge reset]; |
||||
return bridge; |
||||
} |
||||
|
||||
- (void)send:(id)data { |
||||
[self send:data responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { |
||||
[_base sendData:data responseCallback:responseCallback handlerName:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName { |
||||
[self callHandler:handlerName data:nil responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName data:(id)data { |
||||
[self callHandler:handlerName data:data responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { |
||||
[_base sendData:data responseCallback:responseCallback handlerName:handlerName]; |
||||
} |
||||
|
||||
- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { |
||||
_base.messageHandlers[handlerName] = [handler copy]; |
||||
} |
||||
|
||||
- (void)removeHandler:(NSString *)handlerName { |
||||
[_base.messageHandlers removeObjectForKey:handlerName]; |
||||
} |
||||
|
||||
- (void)reset { |
||||
[_base reset]; |
||||
} |
||||
|
||||
- (void)setWebViewDelegate:(id<WKNavigationDelegate>)webViewDelegate { |
||||
_webViewDelegate = webViewDelegate; |
||||
} |
||||
|
||||
- (void)disableJavscriptAlertBoxSafetyTimeout { |
||||
[_base disableJavscriptAlertBoxSafetyTimeout]; |
||||
} |
||||
|
||||
/* Internals |
||||
***********/ |
||||
|
||||
- (void)dealloc { |
||||
_base = nil; |
||||
_webView = nil; |
||||
_webViewDelegate = nil; |
||||
_webView.navigationDelegate = nil; |
||||
} |
||||
|
||||
|
||||
/* WKWebView Specific Internals |
||||
******************************/ |
||||
|
||||
- (void) _setupInstance:(WKWebView*)webView { |
||||
_webView = webView; |
||||
_webView.navigationDelegate = self; |
||||
_base = [[WebViewJavascriptBridgeBase alloc] init]; |
||||
_base.delegate = self; |
||||
} |
||||
|
||||
|
||||
- (void)WKFlushMessageQueue { |
||||
[_webView evaluateJavaScript:[_base webViewJavascriptFetchQueyCommand] completionHandler:^(NSString* result, NSError* error) { |
||||
if (error != nil) { |
||||
NSLog(@"WebViewJavascriptBridge: WARNING: Error when trying to fetch data from WKWebView: %@", error); |
||||
} |
||||
[_base flushMessageQueue:result]; |
||||
}]; |
||||
} |
||||
|
||||
- (void)webView:(WKWebView *)webView didFinishNavigation:(WKNavigation *)navigation { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFinishNavigation:)]) { |
||||
[strongDelegate webView:webView didFinishNavigation:navigation]; |
||||
} |
||||
} |
||||
|
||||
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationResponse:(WKNavigationResponse *)navigationResponse decisionHandler:(void (^)(WKNavigationResponsePolicy))decisionHandler { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationResponse:decisionHandler:)]) { |
||||
[strongDelegate webView:webView decidePolicyForNavigationResponse:navigationResponse decisionHandler:decisionHandler]; |
||||
} |
||||
else { |
||||
decisionHandler(WKNavigationResponsePolicyAllow); |
||||
} |
||||
} |
||||
|
||||
- (void)webView:(WKWebView *)webView didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition, NSURLCredential *))completionHandler { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didReceiveAuthenticationChallenge:completionHandler:)]) { |
||||
[strongDelegate webView:webView didReceiveAuthenticationChallenge:challenge completionHandler:completionHandler]; |
||||
} else { |
||||
completionHandler(NSURLSessionAuthChallengePerformDefaultHandling, nil); |
||||
} |
||||
} |
||||
|
||||
- (void)webView:(WKWebView *)webView decidePolicyForNavigationAction:(WKNavigationAction *)navigationAction decisionHandler:(void (^)(WKNavigationActionPolicy))decisionHandler { |
||||
if (webView != _webView) { return; } |
||||
NSURL *url = navigationAction.request.URL; |
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
|
||||
if ([_base isWebViewJavascriptBridgeURL:url]) { |
||||
if ([_base isBridgeLoadedURL:url]) { |
||||
[_base injectJavascriptFile]; |
||||
} else if ([_base isQueueMessageURL:url]) { |
||||
[self WKFlushMessageQueue]; |
||||
} else { |
||||
[_base logUnkownMessage:url]; |
||||
} |
||||
decisionHandler(WKNavigationActionPolicyCancel); |
||||
return; |
||||
} |
||||
|
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:decisionHandler:)]) { |
||||
[_webViewDelegate webView:webView decidePolicyForNavigationAction:navigationAction decisionHandler:decisionHandler]; |
||||
} else { |
||||
decisionHandler(WKNavigationActionPolicyAllow); |
||||
} |
||||
} |
||||
|
||||
- (void)webView:(WKWebView *)webView didStartProvisionalNavigation:(WKNavigation *)navigation { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didStartProvisionalNavigation:)]) { |
||||
[strongDelegate webView:webView didStartProvisionalNavigation:navigation]; |
||||
} |
||||
} |
||||
|
||||
|
||||
- (void)webView:(WKWebView *)webView didFailNavigation:(WKNavigation *)navigation withError:(NSError *)error { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailNavigation:withError:)]) { |
||||
[strongDelegate webView:webView didFailNavigation:navigation withError:error]; |
||||
} |
||||
} |
||||
|
||||
- (void)webView:(WKWebView *)webView didFailProvisionalNavigation:(WKNavigation *)navigation withError:(NSError *)error { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong typeof(_webViewDelegate) strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailProvisionalNavigation:withError:)]) { |
||||
[strongDelegate webView:webView didFailProvisionalNavigation:navigation withError:error]; |
||||
} |
||||
} |
||||
|
||||
- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { |
||||
[_webView evaluateJavaScript:javascriptCommand completionHandler:nil]; |
||||
return NULL; |
||||
} |
||||
|
||||
|
||||
|
||||
@end |
||||
|
||||
|
||||
#endif |
@ -0,0 +1,50 @@ |
||||
//
|
||||
// WebViewJavascriptBridge.h
|
||||
// ExampleApp-iOS
|
||||
//
|
||||
// Created by Marcus Westin on 6/14/13.
|
||||
// Copyright (c) 2013 Marcus Westin. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h> |
||||
#import "WebViewJavascriptBridgeBase.h" |
||||
|
||||
#if (__MAC_OS_X_VERSION_MAX_ALLOWED > __MAC_10_9 || __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_7_1) |
||||
#define supportsWKWebView |
||||
#endif |
||||
|
||||
#if defined supportsWKWebView |
||||
#import <WebKit/WebKit.h> |
||||
#endif |
||||
|
||||
#if defined __MAC_OS_X_VERSION_MAX_ALLOWED |
||||
#define WVJB_PLATFORM_OSX |
||||
#define WVJB_WEBVIEW_TYPE WebView |
||||
#define WVJB_WEBVIEW_DELEGATE_TYPE NSObject<WebViewJavascriptBridgeBaseDelegate> |
||||
#define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject<WebViewJavascriptBridgeBaseDelegate, WebPolicyDelegate> |
||||
#elif defined __IPHONE_OS_VERSION_MAX_ALLOWED |
||||
#import <UIKit/UIWebView.h> |
||||
#define WVJB_PLATFORM_IOS |
||||
#define WVJB_WEBVIEW_TYPE UIWebView |
||||
#define WVJB_WEBVIEW_DELEGATE_TYPE NSObject<UIWebViewDelegate> |
||||
#define WVJB_WEBVIEW_DELEGATE_INTERFACE NSObject<UIWebViewDelegate, WebViewJavascriptBridgeBaseDelegate> |
||||
#endif |
||||
|
||||
@interface WebViewJavascriptBridge : WVJB_WEBVIEW_DELEGATE_INTERFACE |
||||
|
||||
|
||||
+ (instancetype)bridgeForWebView:(id)webView; |
||||
+ (instancetype)bridge:(id)webView; |
||||
|
||||
+ (void)enableLogging; |
||||
+ (void)setLogMaxLength:(int)length; |
||||
|
||||
- (void)registerHandler:(NSString*)handlerName handler:(WVJBHandler)handler; |
||||
- (void)removeHandler:(NSString*)handlerName; |
||||
- (void)callHandler:(NSString*)handlerName; |
||||
- (void)callHandler:(NSString*)handlerName data:(id)data; |
||||
- (void)callHandler:(NSString*)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback; |
||||
- (void)setWebViewDelegate:(id)webViewDelegate; |
||||
- (void)disableJavscriptAlertBoxSafetyTimeout; |
||||
|
||||
@end |
@ -0,0 +1,211 @@ |
||||
// |
||||
// WebViewJavascriptBridge.m |
||||
// ExampleApp-iOS |
||||
// |
||||
// Created by Marcus Westin on 6/14/13. |
||||
// Copyright (c) 2013 Marcus Westin. All rights reserved. |
||||
// |
||||
|
||||
#import "WebViewJavascriptBridge.h" |
||||
|
||||
#if defined(supportsWKWebView) |
||||
#import "WKWebViewJavascriptBridge.h" |
||||
#endif |
||||
|
||||
#if __has_feature(objc_arc_weak) |
||||
#define WVJB_WEAK __weak |
||||
#else |
||||
#define WVJB_WEAK __unsafe_unretained |
||||
#endif |
||||
|
||||
@implementation WebViewJavascriptBridge { |
||||
WVJB_WEAK WVJB_WEBVIEW_TYPE* _webView; |
||||
WVJB_WEAK id _webViewDelegate; |
||||
long _uniqueId; |
||||
WebViewJavascriptBridgeBase *_base; |
||||
} |
||||
|
||||
/* API |
||||
*****/ |
||||
|
||||
+ (void)enableLogging { |
||||
[WebViewJavascriptBridgeBase enableLogging]; |
||||
} |
||||
+ (void)setLogMaxLength:(int)length { |
||||
[WebViewJavascriptBridgeBase setLogMaxLength:length]; |
||||
} |
||||
|
||||
+ (instancetype)bridgeForWebView:(id)webView { |
||||
return [self bridge:webView]; |
||||
} |
||||
+ (instancetype)bridge:(id)webView { |
||||
#if defined supportsWKWebView |
||||
if ([webView isKindOfClass:[WKWebView class]]) { |
||||
return (WebViewJavascriptBridge*) [WKWebViewJavascriptBridge bridgeForWebView:webView]; |
||||
} |
||||
#endif |
||||
if ([webView isKindOfClass:[WVJB_WEBVIEW_TYPE class]]) { |
||||
WebViewJavascriptBridge* bridge = [[self alloc] init]; |
||||
[bridge _platformSpecificSetup:webView]; |
||||
return bridge; |
||||
} |
||||
[NSException raise:@"BadWebViewType" format:@"Unknown web view type."]; |
||||
return nil; |
||||
} |
||||
|
||||
- (void)setWebViewDelegate:(WVJB_WEBVIEW_DELEGATE_TYPE*)webViewDelegate { |
||||
_webViewDelegate = webViewDelegate; |
||||
} |
||||
|
||||
- (void)send:(id)data { |
||||
[self send:data responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)send:(id)data responseCallback:(WVJBResponseCallback)responseCallback { |
||||
[_base sendData:data responseCallback:responseCallback handlerName:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName { |
||||
[self callHandler:handlerName data:nil responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName data:(id)data { |
||||
[self callHandler:handlerName data:data responseCallback:nil]; |
||||
} |
||||
|
||||
- (void)callHandler:(NSString *)handlerName data:(id)data responseCallback:(WVJBResponseCallback)responseCallback { |
||||
[_base sendData:data responseCallback:responseCallback handlerName:handlerName]; |
||||
} |
||||
|
||||
- (void)registerHandler:(NSString *)handlerName handler:(WVJBHandler)handler { |
||||
_base.messageHandlers[handlerName] = [handler copy]; |
||||
} |
||||
|
||||
- (void)removeHandler:(NSString *)handlerName { |
||||
[_base.messageHandlers removeObjectForKey:handlerName]; |
||||
} |
||||
|
||||
- (void)disableJavscriptAlertBoxSafetyTimeout { |
||||
[_base disableJavscriptAlertBoxSafetyTimeout]; |
||||
} |
||||
|
||||
|
||||
/* Platform agnostic internals |
||||
*****************************/ |
||||
|
||||
- (void)dealloc { |
||||
[self _platformSpecificDealloc]; |
||||
_base = nil; |
||||
_webView = nil; |
||||
_webViewDelegate = nil; |
||||
} |
||||
|
||||
- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand { |
||||
return [_webView stringByEvaluatingJavaScriptFromString:javascriptCommand]; |
||||
} |
||||
|
||||
#if defined WVJB_PLATFORM_OSX |
||||
/* Platform specific internals: OSX |
||||
**********************************/ |
||||
|
||||
- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { |
||||
_webView = webView; |
||||
_webView.policyDelegate = self; |
||||
_base = [[WebViewJavascriptBridgeBase alloc] init]; |
||||
_base.delegate = self; |
||||
} |
||||
|
||||
- (void) _platformSpecificDealloc { |
||||
_webView.policyDelegate = nil; |
||||
} |
||||
|
||||
- (void)webView:(WebView *)webView decidePolicyForNavigationAction:(NSDictionary *)actionInformation request:(NSURLRequest *)request frame:(WebFrame *)frame decisionListener:(id<WebPolicyDecisionListener>)listener { |
||||
if (webView != _webView) { return; } |
||||
|
||||
NSURL *url = [request URL]; |
||||
if ([_base isWebViewJavascriptBridgeURL:url]) { |
||||
if ([_base isBridgeLoadedURL:url]) { |
||||
[_base injectJavascriptFile]; |
||||
} else if ([_base isQueueMessageURL:url]) { |
||||
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; |
||||
[_base flushMessageQueue:messageQueueString]; |
||||
} else { |
||||
[_base logUnkownMessage:url]; |
||||
} |
||||
[listener ignore]; |
||||
} else if (_webViewDelegate && [_webViewDelegate respondsToSelector:@selector(webView:decidePolicyForNavigationAction:request:frame:decisionListener:)]) { |
||||
[_webViewDelegate webView:webView decidePolicyForNavigationAction:actionInformation request:request frame:frame decisionListener:listener]; |
||||
} else { |
||||
[listener use]; |
||||
} |
||||
} |
||||
|
||||
|
||||
|
||||
#elif defined WVJB_PLATFORM_IOS |
||||
/* Platform specific internals: iOS |
||||
**********************************/ |
||||
|
||||
- (void) _platformSpecificSetup:(WVJB_WEBVIEW_TYPE*)webView { |
||||
_webView = webView; |
||||
_webView.delegate = self; |
||||
_base = [[WebViewJavascriptBridgeBase alloc] init]; |
||||
_base.delegate = self; |
||||
} |
||||
|
||||
- (void) _platformSpecificDealloc { |
||||
_webView.delegate = nil; |
||||
} |
||||
|
||||
- (void)webViewDidFinishLoad:(UIWebView *)webView { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { |
||||
[strongDelegate webViewDidFinishLoad:webView]; |
||||
} |
||||
} |
||||
|
||||
- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:didFailLoadWithError:)]) { |
||||
[strongDelegate webView:webView didFailLoadWithError:error]; |
||||
} |
||||
} |
||||
|
||||
- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType { |
||||
if (webView != _webView) { return YES; } |
||||
|
||||
NSURL *url = [request URL]; |
||||
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; |
||||
if ([_base isWebViewJavascriptBridgeURL:url]) { |
||||
if ([_base isBridgeLoadedURL:url]) { |
||||
[_base injectJavascriptFile]; |
||||
} else if ([_base isQueueMessageURL:url]) { |
||||
NSString *messageQueueString = [self _evaluateJavascript:[_base webViewJavascriptFetchQueyCommand]]; |
||||
[_base flushMessageQueue:messageQueueString]; |
||||
} else { |
||||
[_base logUnkownMessage:url]; |
||||
} |
||||
return NO; |
||||
} else if (strongDelegate && [strongDelegate respondsToSelector:@selector(webView:shouldStartLoadWithRequest:navigationType:)]) { |
||||
return [strongDelegate webView:webView shouldStartLoadWithRequest:request navigationType:navigationType]; |
||||
} else { |
||||
return YES; |
||||
} |
||||
} |
||||
|
||||
- (void)webViewDidStartLoad:(UIWebView *)webView { |
||||
if (webView != _webView) { return; } |
||||
|
||||
__strong WVJB_WEBVIEW_DELEGATE_TYPE* strongDelegate = _webViewDelegate; |
||||
if (strongDelegate && [strongDelegate respondsToSelector:@selector(webViewDidStartLoad:)]) { |
||||
[strongDelegate webViewDidStartLoad:webView]; |
||||
} |
||||
} |
||||
|
||||
#endif |
||||
|
||||
@end |
@ -0,0 +1,46 @@ |
||||
//
|
||||
// WebViewJavascriptBridgeBase.h
|
||||
//
|
||||
// Created by @LokiMeyburg on 10/15/14.
|
||||
// Copyright (c) 2014 @LokiMeyburg. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h> |
||||
|
||||
#define kOldProtocolScheme @"wvjbscheme" |
||||
#define kNewProtocolScheme @"https" |
||||
#define kQueueHasMessage @"__wvjb_queue_message__" |
||||
#define kBridgeLoaded @"__bridge_loaded__" |
||||
|
||||
typedef void (^WVJBResponseCallback)(id responseData); |
||||
typedef void (^WVJBHandler)(id data, WVJBResponseCallback responseCallback); |
||||
typedef NSDictionary WVJBMessage; |
||||
|
||||
@protocol WebViewJavascriptBridgeBaseDelegate <NSObject> |
||||
- (NSString*) _evaluateJavascript:(NSString*)javascriptCommand; |
||||
@end |
||||
|
||||
@interface WebViewJavascriptBridgeBase : NSObject |
||||
|
||||
|
||||
@property (weak, nonatomic) id <WebViewJavascriptBridgeBaseDelegate> delegate; |
||||
@property (strong, nonatomic) NSMutableArray* startupMessageQueue; |
||||
@property (strong, nonatomic) NSMutableDictionary* responseCallbacks; |
||||
@property (strong, nonatomic) NSMutableDictionary* messageHandlers; |
||||
@property (strong, nonatomic) WVJBHandler messageHandler; |
||||
|
||||
+ (void)enableLogging; |
||||
+ (void)setLogMaxLength:(int)length; |
||||
- (void)reset; |
||||
- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName; |
||||
- (void)flushMessageQueue:(NSString *)messageQueueString; |
||||
- (void)injectJavascriptFile; |
||||
- (BOOL)isWebViewJavascriptBridgeURL:(NSURL*)url; |
||||
- (BOOL)isQueueMessageURL:(NSURL*)urll; |
||||
- (BOOL)isBridgeLoadedURL:(NSURL*)urll; |
||||
- (void)logUnkownMessage:(NSURL*)url; |
||||
- (NSString *)webViewJavascriptCheckCommand; |
||||
- (NSString *)webViewJavascriptFetchQueyCommand; |
||||
- (void)disableJavscriptAlertBoxSafetyTimeout; |
||||
|
||||
@end |
@ -0,0 +1,221 @@ |
||||
// |
||||
// WebViewJavascriptBridgeBase.m |
||||
// |
||||
// Created by @LokiMeyburg on 10/15/14. |
||||
// Copyright (c) 2014 @LokiMeyburg. All rights reserved. |
||||
// |
||||
|
||||
#import <Foundation/Foundation.h> |
||||
#import "WebViewJavascriptBridgeBase.h" |
||||
#import "WebViewJavascriptBridge_JS.h" |
||||
|
||||
@implementation WebViewJavascriptBridgeBase { |
||||
__weak id _webViewDelegate; |
||||
long _uniqueId; |
||||
} |
||||
|
||||
static bool logging = false; |
||||
static int logMaxLength = 500; |
||||
|
||||
+ (void)enableLogging { logging = true; } |
||||
+ (void)setLogMaxLength:(int)length { logMaxLength = length;} |
||||
|
||||
- (id)init { |
||||
if (self = [super init]) { |
||||
self.messageHandlers = [NSMutableDictionary dictionary]; |
||||
self.startupMessageQueue = [NSMutableArray array]; |
||||
self.responseCallbacks = [NSMutableDictionary dictionary]; |
||||
_uniqueId = 0; |
||||
} |
||||
return self; |
||||
} |
||||
|
||||
- (void)dealloc { |
||||
self.startupMessageQueue = nil; |
||||
self.responseCallbacks = nil; |
||||
self.messageHandlers = nil; |
||||
} |
||||
|
||||
- (void)reset { |
||||
self.startupMessageQueue = [NSMutableArray array]; |
||||
self.responseCallbacks = [NSMutableDictionary dictionary]; |
||||
_uniqueId = 0; |
||||
} |
||||
|
||||
- (void)sendData:(id)data responseCallback:(WVJBResponseCallback)responseCallback handlerName:(NSString*)handlerName { |
||||
NSMutableDictionary* message = [NSMutableDictionary dictionary]; |
||||
|
||||
if (data) { |
||||
message[@"data"] = data; |
||||
} |
||||
|
||||
if (responseCallback) { |
||||
NSString* callbackId = [NSString stringWithFormat:@"objc_cb_%ld", ++_uniqueId]; |
||||
self.responseCallbacks[callbackId] = [responseCallback copy]; |
||||
message[@"callbackId"] = callbackId; |
||||
} |
||||
|
||||
if (handlerName) { |
||||
message[@"handlerName"] = handlerName; |
||||
} |
||||
[self _queueMessage:message]; |
||||
} |
||||
|
||||
- (void)flushMessageQueue:(NSString *)messageQueueString{ |
||||
if (messageQueueString == nil || messageQueueString.length == 0) { |
||||
NSLog(@"WebViewJavascriptBridge: WARNING: ObjC got nil while fetching the message queue JSON from webview. This can happen if the WebViewJavascriptBridge JS is not currently present in the webview, e.g if the webview just loaded a new page."); |
||||
return; |
||||
} |
||||
|
||||
id messages = [self _deserializeMessageJSON:messageQueueString]; |
||||
for (WVJBMessage* message in messages) { |
||||
if (![message isKindOfClass:[WVJBMessage class]]) { |
||||
NSLog(@"WebViewJavascriptBridge: WARNING: Invalid %@ received: %@", [message class], message); |
||||
continue; |
||||
} |
||||
[self _log:@"RCVD" json:message]; |
||||
|
||||
NSString* responseId = message[@"responseId"]; |
||||
if (responseId) { |
||||
WVJBResponseCallback responseCallback = _responseCallbacks[responseId]; |
||||
responseCallback(message[@"responseData"]); |
||||
[self.responseCallbacks removeObjectForKey:responseId]; |
||||
} else { |
||||
WVJBResponseCallback responseCallback = NULL; |
||||
NSString* callbackId = message[@"callbackId"]; |
||||
if (callbackId) { |
||||
responseCallback = ^(id responseData) { |
||||
if (responseData == nil) { |
||||
responseData = [NSNull null]; |
||||
} |
||||
|
||||
WVJBMessage* msg = @{ @"responseId":callbackId, @"responseData":responseData }; |
||||
[self _queueMessage:msg]; |
||||
}; |
||||
} else { |
||||
responseCallback = ^(id ignoreResponseData) { |
||||
// Do nothing |
||||
}; |
||||
} |
||||
|
||||
WVJBHandler handler = self.messageHandlers[message[@"handlerName"]]; |
||||
|
||||
if (!handler) { |
||||
NSLog(@"WVJBNoHandlerException, No handler for message from JS: %@", message); |
||||
continue; |
||||
} |
||||
|
||||
handler(message[@"data"], responseCallback); |
||||
} |
||||
} |
||||
} |
||||
|
||||
- (void)injectJavascriptFile { |
||||
NSString *js = WebViewJavascriptBridge_js(); |
||||
[self _evaluateJavascript:js]; |
||||
if (self.startupMessageQueue) { |
||||
NSArray* queue = self.startupMessageQueue; |
||||
self.startupMessageQueue = nil; |
||||
for (id queuedMessage in queue) { |
||||
[self _dispatchMessage:queuedMessage]; |
||||
} |
||||
} |
||||
} |
||||
|
||||
- (BOOL)isWebViewJavascriptBridgeURL:(NSURL*)url { |
||||
if (![self isSchemeMatch:url]) { |
||||
return NO; |
||||
} |
||||
return [self isBridgeLoadedURL:url] || [self isQueueMessageURL:url]; |
||||
} |
||||
|
||||
- (BOOL)isSchemeMatch:(NSURL*)url { |
||||
NSString* scheme = url.scheme.lowercaseString; |
||||
return [scheme isEqualToString:kNewProtocolScheme] || [scheme isEqualToString:kOldProtocolScheme]; |
||||
} |
||||
|
||||
- (BOOL)isQueueMessageURL:(NSURL*)url { |
||||
NSString* host = url.host.lowercaseString; |
||||
return [self isSchemeMatch:url] && [host isEqualToString:kQueueHasMessage]; |
||||
} |
||||
|
||||
- (BOOL)isBridgeLoadedURL:(NSURL*)url { |
||||
NSString* host = url.host.lowercaseString; |
||||
return [self isSchemeMatch:url] && [host isEqualToString:kBridgeLoaded]; |
||||
} |
||||
|
||||
- (void)logUnkownMessage:(NSURL*)url { |
||||
NSLog(@"WebViewJavascriptBridge: WARNING: Received unknown WebViewJavascriptBridge command %@", [url absoluteString]); |
||||
} |
||||
|
||||
- (NSString *)webViewJavascriptCheckCommand { |
||||
return @"typeof WebViewJavascriptBridge == \'object\';"; |
||||
} |
||||
|
||||
- (NSString *)webViewJavascriptFetchQueyCommand { |
||||
return @"WebViewJavascriptBridge._fetchQueue();"; |
||||
} |
||||
|
||||
- (void)disableJavscriptAlertBoxSafetyTimeout { |
||||
[self sendData:nil responseCallback:nil handlerName:@"_disableJavascriptAlertBoxSafetyTimeout"]; |
||||
} |
||||
|
||||
// Private |
||||
// ------------------------------------------- |
||||
|
||||
- (void) _evaluateJavascript:(NSString *)javascriptCommand { |
||||
[self.delegate _evaluateJavascript:javascriptCommand]; |
||||
} |
||||
|
||||
- (void)_queueMessage:(WVJBMessage*)message { |
||||
if (self.startupMessageQueue) { |
||||
[self.startupMessageQueue addObject:message]; |
||||
} else { |
||||
[self _dispatchMessage:message]; |
||||
} |
||||
} |
||||
|
||||
- (void)_dispatchMessage:(WVJBMessage*)message { |
||||
NSString *messageJSON = [self _serializeMessage:message pretty:NO]; |
||||
[self _log:@"SEND" json:messageJSON]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\\" withString:@"\\\\"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\"" withString:@"\\\""]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\'" withString:@"\\\'"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\n" withString:@"\\n"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\r" withString:@"\\r"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\f" withString:@"\\f"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2028" withString:@"\\u2028"]; |
||||
messageJSON = [messageJSON stringByReplacingOccurrencesOfString:@"\u2029" withString:@"\\u2029"]; |
||||
|
||||
NSString* javascriptCommand = [NSString stringWithFormat:@"WebViewJavascriptBridge._handleMessageFromObjC('%@');", messageJSON]; |
||||
if ([[NSThread currentThread] isMainThread]) { |
||||
[self _evaluateJavascript:javascriptCommand]; |
||||
|
||||
} else { |
||||
dispatch_sync(dispatch_get_main_queue(), ^{ |
||||
[self _evaluateJavascript:javascriptCommand]; |
||||
}); |
||||
} |
||||
} |
||||
|
||||
- (NSString *)_serializeMessage:(id)message pretty:(BOOL)pretty{ |
||||
return [[NSString alloc] initWithData:[NSJSONSerialization dataWithJSONObject:message options:(NSJSONWritingOptions)(pretty ? NSJSONWritingPrettyPrinted : 0) error:nil] encoding:NSUTF8StringEncoding]; |
||||
} |
||||
|
||||
- (NSArray*)_deserializeMessageJSON:(NSString *)messageJSON { |
||||
return [NSJSONSerialization JSONObjectWithData:[messageJSON dataUsingEncoding:NSUTF8StringEncoding] options:NSJSONReadingAllowFragments error:nil]; |
||||
} |
||||
|
||||
- (void)_log:(NSString *)action json:(id)json { |
||||
if (!logging) { return; } |
||||
if (![json isKindOfClass:[NSString class]]) { |
||||
json = [self _serializeMessage:json pretty:YES]; |
||||
} |
||||
if ([json length] > logMaxLength) { |
||||
NSLog(@"WVJB %@: %@ [...]", action, [json substringToIndex:logMaxLength]); |
||||
} else { |
||||
NSLog(@"WVJB %@: %@", action, json); |
||||
} |
||||
} |
||||
|
||||
@end |
@ -0,0 +1,3 @@ |
||||
#import <Foundation/Foundation.h> |
||||
|
||||
NSString * WebViewJavascriptBridge_js(void); |
@ -0,0 +1,139 @@ |
||||
// This file contains the source for the Javascript side of the |
||||
// WebViewJavascriptBridge. It is plaintext, but converted to an NSString |
||||
// via some preprocessor tricks. |
||||
// |
||||
// Previous implementations of WebViewJavascriptBridge loaded the javascript source |
||||
// from a resource. This worked fine for app developers, but library developers who |
||||
// included the bridge into their library, awkwardly had to ask consumers of their |
||||
// library to include the resource, violating their encapsulation. By including the |
||||
// Javascript as a string resource, the encapsulation of the library is maintained. |
||||
|
||||
#import "WebViewJavascriptBridge_JS.h" |
||||
|
||||
NSString * WebViewJavascriptBridge_js() { |
||||
#define __wvjb_js_func__(x) #x |
||||
|
||||
// BEGIN preprocessorJSCode |
||||
static NSString * preprocessorJSCode = @__wvjb_js_func__( |
||||
;(function() { |
||||
if (window.WebViewJavascriptBridge) { |
||||
return; |
||||
} |
||||
|
||||
if (!window.onerror) { |
||||
window.onerror = function(msg, url, line) { |
||||
console.log("WebViewJavascriptBridge: ERROR:" + msg + "@" + url + ":" + line); |
||||
} |
||||
} |
||||
window.WebViewJavascriptBridge = { |
||||
registerHandler: registerHandler, |
||||
callHandler: callHandler, |
||||
disableJavscriptAlertBoxSafetyTimeout: disableJavscriptAlertBoxSafetyTimeout, |
||||
_fetchQueue: _fetchQueue, |
||||
_handleMessageFromObjC: _handleMessageFromObjC |
||||
}; |
||||
|
||||
var messagingIframe; |
||||
var sendMessageQueue = []; |
||||
var messageHandlers = {}; |
||||
|
||||
var CUSTOM_PROTOCOL_SCHEME = 'https'; |
||||
var QUEUE_HAS_MESSAGE = '__wvjb_queue_message__'; |
||||
|
||||
var responseCallbacks = {}; |
||||
var uniqueId = 1; |
||||
var dispatchMessagesWithTimeoutSafety = true; |
||||
|
||||
function registerHandler(handlerName, handler) { |
||||
messageHandlers[handlerName] = handler; |
||||
} |
||||
|
||||
function callHandler(handlerName, data, responseCallback) { |
||||
if (arguments.length == 2 && typeof data == 'function') { |
||||
responseCallback = data; |
||||
data = null; |
||||
} |
||||
_doSend({ handlerName:handlerName, data:data }, responseCallback); |
||||
} |
||||
function disableJavscriptAlertBoxSafetyTimeout() { |
||||
dispatchMessagesWithTimeoutSafety = false; |
||||
} |
||||
|
||||
function _doSend(message, responseCallback) { |
||||
if (responseCallback) { |
||||
var callbackId = 'cb_'+(uniqueId++)+'_'+new Date().getTime(); |
||||
responseCallbacks[callbackId] = responseCallback; |
||||
message['callbackId'] = callbackId; |
||||
} |
||||
sendMessageQueue.push(message); |
||||
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; |
||||
} |
||||
|
||||
function _fetchQueue() { |
||||
var messageQueueString = JSON.stringify(sendMessageQueue); |
||||
sendMessageQueue = []; |
||||
return messageQueueString; |
||||
} |
||||
|
||||
function _dispatchMessageFromObjC(messageJSON) { |
||||
if (dispatchMessagesWithTimeoutSafety) { |
||||
setTimeout(_doDispatchMessageFromObjC); |
||||
} else { |
||||
_doDispatchMessageFromObjC(); |
||||
} |
||||
|
||||
function _doDispatchMessageFromObjC() { |
||||
var message = JSON.parse(messageJSON); |
||||
var messageHandler; |
||||
var responseCallback; |
||||
|
||||
if (message.responseId) { |
||||
responseCallback = responseCallbacks[message.responseId]; |
||||
if (!responseCallback) { |
||||
return; |
||||
} |
||||
responseCallback(message.responseData); |
||||
delete responseCallbacks[message.responseId]; |
||||
} else { |
||||
if (message.callbackId) { |
||||
var callbackResponseId = message.callbackId; |
||||
responseCallback = function(responseData) { |
||||
_doSend({ handlerName:message.handlerName, responseId:callbackResponseId, responseData:responseData }); |
||||
}; |
||||
} |
||||
|
||||
var handler = messageHandlers[message.handlerName]; |
||||
if (!handler) { |
||||
console.log("WebViewJavascriptBridge: WARNING: no handler for message from ObjC:", message); |
||||
} else { |
||||
handler(message.data, responseCallback); |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
function _handleMessageFromObjC(messageJSON) { |
||||
_dispatchMessageFromObjC(messageJSON); |
||||
} |
||||
|
||||
messagingIframe = document.createElement('iframe'); |
||||
messagingIframe.style.display = 'none'; |
||||
messagingIframe.src = CUSTOM_PROTOCOL_SCHEME + '://' + QUEUE_HAS_MESSAGE; |
||||
document.documentElement.appendChild(messagingIframe); |
||||
|
||||
registerHandler("_disableJavascriptAlertBoxSafetyTimeout", disableJavscriptAlertBoxSafetyTimeout); |
||||
|
||||
setTimeout(_callWVJBCallbacks, 0); |
||||
function _callWVJBCallbacks() { |
||||
var callbacks = window.WVJBCallbacks; |
||||
delete window.WVJBCallbacks; |
||||
for (var i=0; i<callbacks.length; i++) { |
||||
callbacks[i](WebViewJavascriptBridge); |
||||
} |
||||
} |
||||
})(); |
||||
); // END preprocessorJSCode |
||||
|
||||
#undef __wvjb_js_func__ |
||||
return preprocessorJSCode; |
||||
}; |
Loading…
Reference in new issue