rename dir

This commit is contained in:
pengfei.zhou
2019-12-21 23:01:45 +08:00
parent f3c427ee92
commit 98b3d419ff
149 changed files with 0 additions and 124 deletions

62
doric-iOS/.gitignore vendored Normal file
View File

@@ -0,0 +1,62 @@
# 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
*.xcscheme
## Other
*.xccheckout
*.moved-aside
*.xcuserstate
*.xcscmblueprint
.idea
.svn
.DS_Store
## Obj-C/Swift specific
*.hmap
*.ipa
# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# http://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
Pods/
Podfile.lock
ReactNative/yarn.lock
ReactNative/node_modules
# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts
Carthage/Build
BXLife.app.dSYM.zip
*.lock
.clang-format
settings.json
Podfile.local
Podfile
ModulesDebug
.yppSpecBin
.yppSpecCode

View File

@@ -0,0 +1,28 @@
Pod::Spec.new do |s|
s.name = 'DoricCore'
s.version = '0.1.2'
s.summary = 'Doric iOS SDK'
s.description = <<-DESC
Doric iOS SDK for cross platform develpment
DESC
s.homepage = 'https://github.com/doric-pub/doric'
s.license = { :type => 'Apache-2.0', :file => 'LICENSE' }
s.author = { 'pengfei.zhou' => 'pengfeizhou@foxmail.com' }
s.source = { :git => 'https://github.com/doric-pub/doric-iOS.git', :tag => s.version.to_s }
s.ios.deployment_target = '8.0'
s.source_files = 'Pod/Classes/**/*'
s.resource_bundles = {
'Doric' => ['Pod/Assets/**/*']
}
s.public_header_files = 'Pod/Classes/**/*.h'
s.dependency 'YYWebImage', '~>1.0.5'
s.dependency 'YYImage/WebP'
s.dependency 'SocketRocket', '~> 0.5.1'
s.dependency 'YYCache', '~> 1.0.4'
end

1
doric-iOS/Example/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
.idea/

View File

@@ -0,0 +1,870 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
26047AF7D618FF60281DC778 /* Pods_Example.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 92C4B99C431BD381198935DE /* Pods_Example.framework */; };
C6AF7EB0B40D76A46B2BB384 /* Pods_ExampleUITests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BF50786B1D1793EC3228133B /* Pods_ExampleUITests.framework */; };
D751D4B065D8D4FA6594B5EE /* DemoVC.m in Sources */ = {isa = PBXBuildFile; fileRef = D751D19E97EF4EDD7588FEBE /* DemoVC.m */; };
D751D4FCC0A2322211DE3D55 /* QRScanViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = D751DA399F1ADB6D34563B5D /* QRScanViewController.m */; };
D751DDB012BAF476A252CD93 /* DemoLibrary.m in Sources */ = {isa = PBXBuildFile; fileRef = D751D2175D09F2C10691FB81 /* DemoLibrary.m */; };
E2334AF022E9D2060098A085 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334AEF22E9D2060098A085 /* AppDelegate.m */; };
E2334AF322E9D2060098A085 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334AF222E9D2060098A085 /* ViewController.m */; };
E2334AF622E9D2060098A085 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E2334AF422E9D2060098A085 /* Main.storyboard */; };
E2334AF822E9D2070098A085 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = E2334AF722E9D2070098A085 /* Assets.xcassets */; };
E2334AFB22E9D2070098A085 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = E2334AF922E9D2070098A085 /* LaunchScreen.storyboard */; };
E2334AFE22E9D2070098A085 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334AFD22E9D2070098A085 /* main.m */; };
E2334B0822E9D2070098A085 /* ExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B0722E9D2070098A085 /* ExampleTests.m */; };
E2334B1322E9D2070098A085 /* ExampleUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = E2334B1222E9D2070098A085 /* ExampleUITests.m */; };
E2F4481723839AC500073C7F /* demo in Resources */ = {isa = PBXBuildFile; fileRef = E2F4481623839AC500073C7F /* demo */; };
E778063CA90E2DD797D11D7C /* Pods_ExampleTests.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 00A2FF6380A526AB267988ED /* Pods_ExampleTests.framework */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
E2334B0422E9D2070098A085 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E2334AE322E9D2060098A085 /* Project object */;
proxyType = 1;
remoteGlobalIDString = E2334AEA22E9D2060098A085;
remoteInfo = Example;
};
E2334B0F22E9D2070098A085 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = E2334AE322E9D2060098A085 /* Project object */;
proxyType = 1;
remoteGlobalIDString = E2334AEA22E9D2060098A085;
remoteInfo = Example;
};
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
00A2FF6380A526AB267988ED /* Pods_ExampleTests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ExampleTests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
016E930415B91D826F9FFF47 /* Pods-ExampleUITests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleUITests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleUITests/Pods-ExampleUITests.debug.xcconfig"; sourceTree = "<group>"; };
3D75F592D76A665674B31A66 /* Pods-Example.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.release.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.release.xcconfig"; sourceTree = "<group>"; };
8231E841CCAF382F85C9F576 /* Pods-Example.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Example.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Example/Pods-Example.debug.xcconfig"; sourceTree = "<group>"; };
92C4B99C431BD381198935DE /* Pods_Example.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_Example.framework; sourceTree = BUILT_PRODUCTS_DIR; };
B93423722F2E06DC238CDD18 /* Pods-ExampleUITests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleUITests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleUITests/Pods-ExampleUITests.release.xcconfig"; sourceTree = "<group>"; };
B93D4DB00FD244178B7CE7C4 /* Pods-ExampleTests.release.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleTests.release.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleTests/Pods-ExampleTests.release.xcconfig"; sourceTree = "<group>"; };
BF50786B1D1793EC3228133B /* Pods_ExampleUITests.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_ExampleUITests.framework; sourceTree = BUILT_PRODUCTS_DIR; };
D751D18AD6496F4A9BE1AB45 /* QRScanViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = QRScanViewController.h; sourceTree = "<group>"; };
D751D19E97EF4EDD7588FEBE /* DemoVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoVC.m; sourceTree = "<group>"; };
D751D2175D09F2C10691FB81 /* DemoLibrary.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DemoLibrary.m; sourceTree = "<group>"; };
D751DA399F1ADB6D34563B5D /* QRScanViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = QRScanViewController.m; sourceTree = "<group>"; };
D751DB0CB3009E12990F661E /* DemoLibrary.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoLibrary.h; sourceTree = "<group>"; };
D751DDEC114E037231257E64 /* DemoVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DemoVC.h; sourceTree = "<group>"; };
D91241144B5A3356A3C60644 /* Pods-ExampleTests.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-ExampleTests.debug.xcconfig"; path = "Pods/Target Support Files/Pods-ExampleTests/Pods-ExampleTests.debug.xcconfig"; sourceTree = "<group>"; };
E2334AEB22E9D2060098A085 /* Doric Playground.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "Doric Playground.app"; sourceTree = BUILT_PRODUCTS_DIR; };
E2334AEE22E9D2060098A085 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
E2334AEF22E9D2060098A085 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
E2334AF122E9D2060098A085 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = "<group>"; };
E2334AF222E9D2060098A085 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = "<group>"; };
E2334AF522E9D2060098A085 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
E2334AF722E9D2070098A085 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
E2334AFA22E9D2070098A085 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
E2334AFC22E9D2070098A085 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E2334AFD22E9D2070098A085 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
E2334B0322E9D2070098A085 /* ExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E2334B0722E9D2070098A085 /* ExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleTests.m; sourceTree = "<group>"; };
E2334B0922E9D2070098A085 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E2334B0E22E9D2070098A085 /* ExampleUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ExampleUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
E2334B1222E9D2070098A085 /* ExampleUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExampleUITests.m; sourceTree = "<group>"; };
E2334B1422E9D2070098A085 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
E2F4481623839AC500073C7F /* demo */ = {isa = PBXFileReference; lastKnownFileType = folder; path = demo; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
E2334AE822E9D2060098A085 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
26047AF7D618FF60281DC778 /* Pods_Example.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334B0022E9D2070098A085 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
E778063CA90E2DD797D11D7C /* Pods_ExampleTests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334B0B22E9D2070098A085 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
C6AF7EB0B40D76A46B2BB384 /* Pods_ExampleUITests.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
6CBE6FA5F47A90E57AB456B2 /* Pods */ = {
isa = PBXGroup;
children = (
8231E841CCAF382F85C9F576 /* Pods-Example.debug.xcconfig */,
3D75F592D76A665674B31A66 /* Pods-Example.release.xcconfig */,
D91241144B5A3356A3C60644 /* Pods-ExampleTests.debug.xcconfig */,
B93D4DB00FD244178B7CE7C4 /* Pods-ExampleTests.release.xcconfig */,
016E930415B91D826F9FFF47 /* Pods-ExampleUITests.debug.xcconfig */,
B93423722F2E06DC238CDD18 /* Pods-ExampleUITests.release.xcconfig */,
);
name = Pods;
sourceTree = "<group>";
};
D80A9B07B39AD04027CAE17B /* Frameworks */ = {
isa = PBXGroup;
children = (
92C4B99C431BD381198935DE /* Pods_Example.framework */,
00A2FF6380A526AB267988ED /* Pods_ExampleTests.framework */,
BF50786B1D1793EC3228133B /* Pods_ExampleUITests.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
E2334AE222E9D2060098A085 = {
isa = PBXGroup;
children = (
E2334AED22E9D2060098A085 /* Example */,
E2334B0622E9D2070098A085 /* ExampleTests */,
E2334B1122E9D2070098A085 /* ExampleUITests */,
E2334AEC22E9D2060098A085 /* Products */,
6CBE6FA5F47A90E57AB456B2 /* Pods */,
D80A9B07B39AD04027CAE17B /* Frameworks */,
);
sourceTree = "<group>";
};
E2334AEC22E9D2060098A085 /* Products */ = {
isa = PBXGroup;
children = (
E2334AEB22E9D2060098A085 /* Doric Playground.app */,
E2334B0322E9D2070098A085 /* ExampleTests.xctest */,
E2334B0E22E9D2070098A085 /* ExampleUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
E2334AED22E9D2060098A085 /* Example */ = {
isa = PBXGroup;
children = (
E2F4481623839AC500073C7F /* demo */,
E2334AEE22E9D2060098A085 /* AppDelegate.h */,
E2334AEF22E9D2060098A085 /* AppDelegate.m */,
E2334AF122E9D2060098A085 /* ViewController.h */,
E2334AF222E9D2060098A085 /* ViewController.m */,
E2334AF422E9D2060098A085 /* Main.storyboard */,
E2334AF722E9D2070098A085 /* Assets.xcassets */,
E2334AFC22E9D2070098A085 /* Info.plist */,
E2334AF922E9D2070098A085 /* LaunchScreen.storyboard */,
E2334AFD22E9D2070098A085 /* main.m */,
D751D19E97EF4EDD7588FEBE /* DemoVC.m */,
D751DDEC114E037231257E64 /* DemoVC.h */,
D751DA399F1ADB6D34563B5D /* QRScanViewController.m */,
D751D18AD6496F4A9BE1AB45 /* QRScanViewController.h */,
D751D2175D09F2C10691FB81 /* DemoLibrary.m */,
D751DB0CB3009E12990F661E /* DemoLibrary.h */,
);
path = Example;
sourceTree = "<group>";
};
E2334B0622E9D2070098A085 /* ExampleTests */ = {
isa = PBXGroup;
children = (
E2334B0722E9D2070098A085 /* ExampleTests.m */,
E2334B0922E9D2070098A085 /* Info.plist */,
);
path = ExampleTests;
sourceTree = "<group>";
};
E2334B1122E9D2070098A085 /* ExampleUITests */ = {
isa = PBXGroup;
children = (
E2334B1222E9D2070098A085 /* ExampleUITests.m */,
E2334B1422E9D2070098A085 /* Info.plist */,
);
path = ExampleUITests;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
E2334AEA22E9D2060098A085 /* Example */ = {
isa = PBXNativeTarget;
buildConfigurationList = E2334B1722E9D2070098A085 /* Build configuration list for PBXNativeTarget "Example" */;
buildPhases = (
BE34CD8291B20D26F2ADE3E1 /* [CP] Check Pods Manifest.lock */,
E24A030C22EED0D500AB4631 /* Package JS Bundle */,
E2334AE722E9D2060098A085 /* Sources */,
E2334AE822E9D2060098A085 /* Frameworks */,
E2334AE922E9D2060098A085 /* Resources */,
223E53E328880489770F8C93 /* [CP] Embed Pods Frameworks */,
EEF1C3B3FE5FE92E603C3B08 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
);
name = Example;
productName = Example;
productReference = E2334AEB22E9D2060098A085 /* Doric Playground.app */;
productType = "com.apple.product-type.application";
};
E2334B0222E9D2070098A085 /* ExampleTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = E2334B1A22E9D2070098A085 /* Build configuration list for PBXNativeTarget "ExampleTests" */;
buildPhases = (
48D050F720D3A879060292A8 /* [CP] Check Pods Manifest.lock */,
E2334AFF22E9D2070098A085 /* Sources */,
E2334B0022E9D2070098A085 /* Frameworks */,
E2334B0122E9D2070098A085 /* Resources */,
9908F148F5F00DD2EB349A08 /* [CP] Embed Pods Frameworks */,
17E0A19B8E5C4C4883C8AB85 /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
E2334B0522E9D2070098A085 /* PBXTargetDependency */,
);
name = ExampleTests;
productName = ExampleTests;
productReference = E2334B0322E9D2070098A085 /* ExampleTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
E2334B0D22E9D2070098A085 /* ExampleUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = E2334B1D22E9D2070098A085 /* Build configuration list for PBXNativeTarget "ExampleUITests" */;
buildPhases = (
074533B9C1C5204E8750B07B /* [CP] Check Pods Manifest.lock */,
E2334B0A22E9D2070098A085 /* Sources */,
E2334B0B22E9D2070098A085 /* Frameworks */,
E2334B0C22E9D2070098A085 /* Resources */,
5FE5475A2ECF1794CBF57C61 /* [CP] Embed Pods Frameworks */,
C09BD0B68592DA6641E3B65D /* [CP] Copy Pods Resources */,
);
buildRules = (
);
dependencies = (
E2334B1022E9D2070098A085 /* PBXTargetDependency */,
);
name = ExampleUITests;
productName = ExampleUITests;
productReference = E2334B0E22E9D2070098A085 /* ExampleUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
E2334AE322E9D2060098A085 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1030;
ORGANIZATIONNAME = pengfei.zhou;
TargetAttributes = {
E2334AEA22E9D2060098A085 = {
CreatedOnToolsVersion = 10.3;
};
E2334B0222E9D2070098A085 = {
CreatedOnToolsVersion = 10.3;
TestTargetID = E2334AEA22E9D2060098A085;
};
E2334B0D22E9D2070098A085 = {
CreatedOnToolsVersion = 10.3;
TestTargetID = E2334AEA22E9D2060098A085;
};
};
};
buildConfigurationList = E2334AE622E9D2060098A085 /* Build configuration list for PBXProject "Example" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = E2334AE222E9D2060098A085;
productRefGroup = E2334AEC22E9D2060098A085 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
E2334AEA22E9D2060098A085 /* Example */,
E2334B0222E9D2070098A085 /* ExampleTests */,
E2334B0D22E9D2070098A085 /* ExampleUITests */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
E2334AE922E9D2060098A085 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2334AFB22E9D2070098A085 /* LaunchScreen.storyboard in Resources */,
E2F4481723839AC500073C7F /* demo in Resources */,
E2334AF822E9D2070098A085 /* Assets.xcassets in Resources */,
E2334AF622E9D2060098A085 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334B0122E9D2070098A085 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334B0C22E9D2070098A085 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXShellScriptBuildPhase section */
074533B9C1C5204E8750B07B /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ExampleUITests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
17E0A19B8E5C4C4883C8AB85 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleTests/Pods-ExampleTests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
223E53E328880489770F8C93 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh",
"${BUILT_PRODUCTS_DIR}/DoricCore/DoricCore.framework",
"${BUILT_PRODUCTS_DIR}/SocketRocket/SocketRocket.framework",
"${BUILT_PRODUCTS_DIR}/YYCache/YYCache.framework",
"${BUILT_PRODUCTS_DIR}/YYImage/YYImage.framework",
"${BUILT_PRODUCTS_DIR}/YYWebImage/YYWebImage.framework",
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/DoricCore.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/SocketRocket.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYCache.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYImage.framework",
"${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/YYWebImage.framework",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
48D050F720D3A879060292A8 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-ExampleTests-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
5FE5475A2ECF1794CBF57C61 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleUITests/Pods-ExampleUITests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
9908F148F5F00DD2EB349A08 /* [CP] Embed Pods Frameworks */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Embed Pods Frameworks";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleTests/Pods-ExampleTests-frameworks.sh\"\n";
showEnvVarsInLog = 0;
};
BE34CD8291B20D26F2ADE3E1 /* [CP] Check Pods Manifest.lock */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
"${PODS_PODFILE_DIR_PATH}/Podfile.lock",
"${PODS_ROOT}/Manifest.lock",
);
name = "[CP] Check Pods Manifest.lock";
outputFileListPaths = (
);
outputPaths = (
"$(DERIVED_FILE_DIR)/Pods-Example-checkManifestLockResult.txt",
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "diff \"${PODS_PODFILE_DIR_PATH}/Podfile.lock\" \"${PODS_ROOT}/Manifest.lock\" > /dev/null\nif [ $? != 0 ] ; then\n # print error to STDERR\n echo \"error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.\" >&2\n exit 1\nfi\n# This output is used by Xcode 'outputs' to avoid re-running this script phase.\necho \"SUCCESS\" > \"${SCRIPT_OUTPUT_FILE_0}\"\n";
showEnvVarsInLog = 0;
};
C09BD0B68592DA6641E3B65D /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-ExampleUITests/Pods-ExampleUITests-resources.sh\"\n";
showEnvVarsInLog = 0;
};
E24A030C22EED0D500AB4631 /* Package JS Bundle */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "Package JS Bundle";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "# Type a script or drag a script file from your workspace to insert its path.\n\nexport NVM_DIR=\"$HOME/.nvm\"\n[ -s \"$NVM_DIR/nvm.sh\" ] && \\. \"$NVM_DIR/nvm.sh\" # This loads nvm\n[ -s \"$NVM_DIR/bash_completion\" ] && \\. \"$NVM_DIR/bash_completion\" # This loads nvm bash_completion\n\nsh ../../bundle.sh\n";
};
EEF1C3B3FE5FE92E603C3B08 /* [CP] Copy Pods Resources */ = {
isa = PBXShellScriptBuildPhase;
buildActionMask = 2147483647;
files = (
);
inputFileListPaths = (
);
inputPaths = (
);
name = "[CP] Copy Pods Resources";
outputFileListPaths = (
);
outputPaths = (
);
runOnlyForDeploymentPostprocessing = 0;
shellPath = /bin/sh;
shellScript = "\"${SRCROOT}/Pods/Target Support Files/Pods-Example/Pods-Example-resources.sh\"\n";
showEnvVarsInLog = 0;
};
/* End PBXShellScriptBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
E2334AE722E9D2060098A085 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2334AF322E9D2060098A085 /* ViewController.m in Sources */,
E2334AFE22E9D2070098A085 /* main.m in Sources */,
E2334AF022E9D2060098A085 /* AppDelegate.m in Sources */,
D751D4B065D8D4FA6594B5EE /* DemoVC.m in Sources */,
D751D4FCC0A2322211DE3D55 /* QRScanViewController.m in Sources */,
D751DDB012BAF476A252CD93 /* DemoLibrary.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334AFF22E9D2070098A085 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2334B0822E9D2070098A085 /* ExampleTests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
E2334B0A22E9D2070098A085 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
E2334B1322E9D2070098A085 /* ExampleUITests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
E2334B0522E9D2070098A085 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = E2334AEA22E9D2060098A085 /* Example */;
targetProxy = E2334B0422E9D2070098A085 /* PBXContainerItemProxy */;
};
E2334B1022E9D2070098A085 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = E2334AEA22E9D2060098A085 /* Example */;
targetProxy = E2334B0F22E9D2070098A085 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin PBXVariantGroup section */
E2334AF422E9D2060098A085 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
E2334AF522E9D2060098A085 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
E2334AF922E9D2070098A085 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
E2334AFA22E9D2070098A085 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */
/* Begin XCBuildConfiguration section */
E2334B1522E9D2070098A085 /* 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.4;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
E2334B1622E9D2070098A085 /* 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.4;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
E2334B1822E9D2070098A085 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 8231E841CCAF382F85C9F576 /* Pods-Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7EE2RX3L3P;
INFOPLIST_FILE = Example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.Example;
PRODUCT_NAME = "Doric Playground";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
E2334B1922E9D2070098A085 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 3D75F592D76A665674B31A66 /* Pods-Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_TEAM = 7EE2RX3L3P;
INFOPLIST_FILE = Example/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.Example;
PRODUCT_NAME = "Doric Playground";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
E2334B1B22E9D2070098A085 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = D91241144B5A3356A3C60644 /* Pods-ExampleTests.debug.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = ExampleTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.ExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
};
name = Debug;
};
E2334B1C22E9D2070098A085 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B93D4DB00FD244178B7CE7C4 /* Pods-ExampleTests.release.xcconfig */;
buildSettings = {
BUNDLE_LOADER = "$(TEST_HOST)";
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = ExampleTests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.ExampleTests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_HOST = "$(BUILT_PRODUCTS_DIR)/Example.app/Example";
};
name = Release;
};
E2334B1E22E9D2070098A085 /* Debug */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = 016E930415B91D826F9FFF47 /* Pods-ExampleUITests.debug.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = ExampleUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.ExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Example;
};
name = Debug;
};
E2334B1F22E9D2070098A085 /* Release */ = {
isa = XCBuildConfiguration;
baseConfigurationReference = B93423722F2E06DC238CDD18 /* Pods-ExampleUITests.release.xcconfig */;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = ExampleUITests/Info.plist;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
"@loader_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = pub.doric.ExampleUITests;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = Example;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
E2334AE622E9D2060098A085 /* Build configuration list for PBXProject "Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E2334B1522E9D2070098A085 /* Debug */,
E2334B1622E9D2070098A085 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E2334B1722E9D2070098A085 /* Build configuration list for PBXNativeTarget "Example" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E2334B1822E9D2070098A085 /* Debug */,
E2334B1922E9D2070098A085 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E2334B1A22E9D2070098A085 /* Build configuration list for PBXNativeTarget "ExampleTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E2334B1B22E9D2070098A085 /* Debug */,
E2334B1C22E9D2070098A085 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
E2334B1D22E9D2070098A085 /* Build configuration list for PBXNativeTarget "ExampleUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
E2334B1E22E9D2070098A085 /* Debug */,
E2334B1F22E9D2070098A085 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = E2334AE322E9D2060098A085 /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:Example.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "group:Example.xcodeproj">
</FileRef>
<FileRef
location = "group:Pods/Pods.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,8 @@
<?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>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

View File

@@ -0,0 +1,17 @@
//
// AppDelegate.h
// Example
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (strong, nonatomic) UIWindow *window;
@end

View File

@@ -0,0 +1,61 @@
//
// AppDelegate.m
// Example
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import "AppDelegate.h"
#import "ViewController.h"
@interface AppDelegate ()
@property(nonatomic, strong) UIViewController *rootVC;
@property(nonatomic, strong) UINavigationController *navigationController;
@end
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.rootVC = [[ViewController alloc] init];
self.window.rootViewController = self.rootVC;
self.navigationController = [[UINavigationController
alloc] initWithRootViewController:self.rootVC];
[self.window addSubview:self.navigationController.view];
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
// 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.
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
// 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.
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
// 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.
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
// 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.
}
- (void)applicationWillTerminate:(UIApplication *)application {
// Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
}
@end

View File

@@ -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"
}
}

View File

@@ -0,0 +1,6 @@
{
"info" : {
"version" : 1,
"author" : "xcode"
}
}

View File

@@ -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>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13122.16" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="BYZ-38-t0r">
<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="tne-QT-ifu">
<objects>
<viewController id="BYZ-38-t0r" customClass="ViewController" customModuleProvider="" sceneMemberID="viewController">
<view key="view" contentMode="scaleToFill" id="8bC-Xf-vdC">
<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="dkx-z0-nzr" sceneMemberID="firstResponder"/>
</objects>
</scene>
</scenes>
</document>

View File

@@ -0,0 +1,10 @@
//
// Created by pengfei.zhou on 2019/12/11.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <DoricCore/Doric.h>
@interface DemoLibrary : DoricLibrary
@end

View File

@@ -0,0 +1,24 @@
//
// Created by pengfei.zhou on 2019/12/11.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import "DemoLibrary.h"
@interface DoricDemoPlugin : DoricNativePlugin
@end
@implementation DoricDemoPlugin
- (void)test {
dispatch_async(dispatch_get_main_queue(), ^{
ShowToast(@"Test called", CENTER);
});
}
@end
@implementation DemoLibrary
- (void)load:(DoricRegistry *)registry {
[registry registerNativePlugin:[DoricDemoPlugin class] withName:@"demo"];
}
@end

View File

@@ -0,0 +1,12 @@
//
// Created by pengfei.zhou on 2019/11/19.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface DemoVC : UIViewController
- (instancetype)initWithPath:(NSString *)filePath;
@end

View File

@@ -0,0 +1,39 @@
//
// Created by pengfei.zhou on 2019/11/19.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import "DemoVC.h"
#import <DoricCore/Doric.h>
@interface DemoVC ()
@property(nonatomic, copy) NSString *filePath;
@end
@implementation DemoVC
- (instancetype)initWithPath:(NSString *)filePath {
if (self = [self init]) {
_filePath = filePath;
}
return self;
}
- (void)viewDidLoad {
self.title = self.filePath;
self.view.backgroundColor = [UIColor whiteColor];
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *demoPath = [path stringByAppendingPathComponent:@"demo"];
NSString *fullPath = [demoPath stringByAppendingPathComponent:self.filePath];
NSString *jsContent = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:nil];
DoricPanel *panel = [DoricPanel new];
[panel.view also:^(UIView *it) {
it.width = self.view.width;
it.height = self.view.height - 88;
it.top = 88;
[self.view addSubview:it];
}];
[self addChildViewController:panel];
[panel config:jsContent alias:self.filePath extra:nil];
}
@end

View File

@@ -0,0 +1,54 @@
<?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>NSCameraUsageDescription</key>
<string>Scan QR Code</string>
<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>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>LSApplicationCategoryType</key>
<string></string>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,10 @@
//
// Created by pengfei.zhou on 2019/11/21.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@interface QRScanViewController : UIViewController
@end

View File

@@ -0,0 +1,93 @@
//
// Created by pengfei.zhou on 2019/11/21.
// Copyright (c) 2019 pengfei.zhou. All rights reserved.
//
#import "QRScanViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <DoricCore/Doric.h>
@interface QRScanViewController () <AVCaptureMetadataOutputObjectsDelegate>
@property(strong, nonatomic) AVCaptureDevice *device;
@property(strong, nonatomic) AVCaptureDeviceInput *input;
@property(strong, nonatomic) AVCaptureMetadataOutput *output;
@property(strong, nonatomic) AVCaptureSession *session;
@property(strong, nonatomic) AVCaptureVideoPreviewLayer *previewLayer;
@property(strong, nonatomic) UIPinchGestureRecognizer *pinchGes;
@property(assign, nonatomic) CGFloat scanRegion_W;
@property(assign, nonatomic) CGFloat initScale;
@end
@implementation QRScanViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"扫一扫";
[self configBasicDevice];
[self configPinchGes];
[self.session startRunning];
}
- (void)configBasicDevice {
self.device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
self.input = [[AVCaptureDeviceInput alloc] initWithDevice:self.device error:nil];
self.output = [[AVCaptureMetadataOutput alloc] init];
[self.output setMetadataObjectsDelegate:self queue:dispatch_get_main_queue()];
self.session = [[AVCaptureSession alloc] init];
[self.session setSessionPreset:AVCaptureSessionPresetHigh];
if ([self.session canAddInput:self.input]) {
[self.session addInput:self.input];
}
if ([self.session canAddOutput:self.output]) {
[self.session addOutput:self.output];
}
[self.output setMetadataObjectTypes:@[AVMetadataObjectTypeQRCode]];
[self.output setRectOfInterest:CGRectMake(0, 0, 1, 1)];
self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.previewLayer.frame = CGRectMake(0, 0, self.view.width, self.view.height);
self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
[self.view.layer addSublayer:self.previewLayer];
}
- (void)configPinchGes {
self.pinchGes = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(pinchDetected:)];
[self.view addGestureRecognizer:self.pinchGes];
}
- (void)pinchDetected:(UIPinchGestureRecognizer *)recogniser {
if (!_device) {
return;
}
if (recogniser.state == UIGestureRecognizerStateBegan) {
_initScale = _device.videoZoomFactor;
}
NSError *error = nil;
[_device lockForConfiguration:&error];
if (!error) {
CGFloat zoomFactor;
CGFloat scale = recogniser.scale;
if (scale < 1.0f) {
zoomFactor = self.initScale - pow(self.device.activeFormat.videoMaxZoomFactor, 1.0f - recogniser.scale);
} else {
zoomFactor = self.initScale + pow(self.device.activeFormat.videoMaxZoomFactor, (recogniser.scale - 1.0f) / 2.0f);
}
zoomFactor = MIN(15.0f, zoomFactor);
zoomFactor = MAX(1.0f, zoomFactor);
_device.videoZoomFactor = zoomFactor;
[_device unlockForConfiguration];
}
}
#pragma mark - AVCaptureMetadataOutputObjectsDelegate
- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputMetadataObjects:(NSArray *)metadataObjects fromConnection:(AVCaptureConnection *)connection {
[self.session stopRunning];
if ([metadataObjects count] >= 1) {
AVMetadataMachineReadableCodeObject *qrObject = [metadataObjects lastObject];
NSString *result = qrObject.stringValue;
NSLog(@"Scan result is %@", result);
[[DoricDriver instance] connectDevKit:[NSString stringWithFormat:@"ws://%@:7777", result]];
ShowToast([NSString stringWithFormat:@"Connected to %@", result], BOTTOM);
[self.navigationController popViewControllerAnimated:NO];
}
}
@end

View File

@@ -0,0 +1,15 @@
//
// ViewController.h
// Example
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@end

View File

@@ -0,0 +1,92 @@
//
// ViewController.m
// Example
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import "ViewController.h"
#import <DoricCore/Doric.h>
#import "DemoVC.h"
#import "QRScanViewController.h"
#import "DemoLibrary.h"
@interface ViewController () <UITableViewDelegate, UITableViewDataSource>
@property(nonatomic, copy) NSArray <NSString *> *demoFilePaths;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
self.title = @"Doric Demo";
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *demoPath = [path stringByAppendingPathComponent:@"demo"];
NSFileManager *mgr = [NSFileManager defaultManager];
self.demoFilePaths = [[mgr subpathsAtPath:demoPath] filter:^BOOL(NSString *obj) {
return ![obj containsString:@".map"];
}];
NSMutableArray <NSString *> *tmp = [self.demoFilePaths mutableCopy];
NSStringCompareOptions comparisonOptions = NSCaseInsensitiveSearch | NSNumericSearch | NSWidthInsensitiveSearch | NSForcedOrderingSearch;
[tmp sortUsingComparator:^NSComparisonResult(NSString *obj1, NSString *obj2) {
NSRange range = NSMakeRange(0, obj1.length);
return [obj1 compare:obj2 options:comparisonOptions range:range];
}];
[tmp insertObject:@"Dev Kit" atIndex:0];
self.demoFilePaths = tmp;
[self.view addSubview:[[UITableView new] also:^(UITableView *it) {
it.width = self.view.width;
it.height = self.view.height;
it.left = it.top = 0;
it.dataSource = self;
it.delegate = self;
}]];
[DoricRegistry register:[DemoLibrary new]];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.demoFilePaths.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
NSString *path = self.demoFilePaths[(NSUInteger) indexPath.row];
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"cell"];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"cellID"];
cell.selectionStyle = UITableViewCellSelectionStyleNone;
}
cell.textLabel.text = path;
return cell;
}
- (BOOL)isSimulator {
return TARGET_OS_SIMULATOR == 1;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
if (indexPath.row == 0) {
if (self.isSimulator) {
NSString *result = @"127.0.0.1";
[[DoricDriver instance] connectDevKit:[NSString stringWithFormat:@"ws://%@:7777", result]];
ShowToast([NSString stringWithFormat:@"Connected to %@", result], BOTTOM);
} else {
[self.navigationController pushViewController:[QRScanViewController new] animated:NO];
}
return;
}
NSString *file = self.demoFilePaths[(NSUInteger) indexPath.row];
if ([file containsString:@"NavigatorDemo"]) {
DoricViewController *doricViewController = [[DoricViewController alloc]
initWithScheme:[NSString stringWithFormat:@"assets://demo/%@", file]
alias:self.demoFilePaths[(NSUInteger) indexPath.row]
extra:nil
];
[self.navigationController pushViewController:doricViewController animated:NO];
} else {
DemoVC *demoVC = [[DemoVC alloc] initWithPath:file];
[self.navigationController pushViewController:demoVC animated:NO];
}
}
@end

View File

@@ -0,0 +1 @@
*.js

View File

@@ -0,0 +1,16 @@
//
// main.m
// Example
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import <UIKit/UIKit.h>
#import "AppDelegate.h"
int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

View File

@@ -0,0 +1,37 @@
//
// ExampleTests.m
// ExampleTests
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface ExampleTests : XCTestCase
@end
@implementation ExampleTests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// This is an example of a functional test case.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
- (void)testPerformanceExample {
// This is an example of a performance test case.
[self measureBlock:^{
// Put the code you want to measure the time of here.
}];
}
@end

View File

@@ -0,0 +1,22 @@
<?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>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -0,0 +1,38 @@
//
// ExampleUITests.m
// ExampleUITests
//
// Created by pengfei.zhou on 2019/7/25.
// Copyright © 2019 pengfei.zhou. All rights reserved.
//
#import <XCTest/XCTest.h>
@interface ExampleUITests : XCTestCase
@end
@implementation ExampleUITests
- (void)setUp {
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
[[[XCUIApplication alloc] init] launch];
// In UI tests its important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
}
- (void)testExample {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}
@end

View File

@@ -0,0 +1,22 @@
<?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>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

201
doric-iOS/LICENSE Normal file
View File

@@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [2019] [Doric.Pub]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

View File

@@ -0,0 +1 @@
*.js

View File

View File

@@ -0,0 +1,33 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// WSClient.h
// Doric
//
// Created by pengfei.zhou on 2019/8/14.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface DoricWSClient : NSObject
- (instancetype)initWithUrl:(NSString *)url;
- (void)close;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,81 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// WSClient.m
// Doric
//
// Created by pengfei.zhou on 2019/8/14.
//
#import "DoricWSClient.h"
#import <SocketRocket/SRWebSocket.h>
#import "DoricUtil.h"
#import "DoricContextManager.h"
@interface DoricWSClient () <SRWebSocketDelegate>
@property(nonatomic, strong) SRWebSocket *websocket;
@end
@implementation DoricWSClient
- (instancetype)initWithUrl:(NSString *)url {
if (self = [super init]) {
_websocket = [[SRWebSocket alloc] initWithURL:[NSURL URLWithString:url]];
_websocket.delegate = self;
[_websocket open];
}
return self;
}
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
DoricLog(@"webSocketDidOpen");
}
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
DoricLog(@"webSocketdidReceivePong");
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&err];
if (err) {
DoricLog(@"webSocketdidReceiveMessage parse error%@", err);
return;
}
NSString *source = [[dic valueForKey:@"source"] mutableCopy];
NSString *script = [dic valueForKey:@"script"];
for (NSValue *value in [[DoricContextManager instance] aliveContexts]) {
DoricContext *context = value.nonretainedObjectValue;
if ([source containsString:context.source]) {
[context reload:script];
}
}
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
DoricLog(@"webSocketdidFailWithError");
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
DoricLog(@"webSocketdidCloseWithCode");
}
- (void)close {
[self.websocket close];
}
@end

View File

@@ -0,0 +1,30 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "DoricContext.h"
#import "DoricLayouts.h"
#import "DoricExtensions.h"
#import "DoricViewNode.h"
#import "DoricRootNode.h"
#import "UIView+Doric.h"
#import "DoricUtil.h"
#import "DoricPanel.h"
#import "DoricJSLoaderManager.h"
#import "DoricNavigatorDelegate.h"
#import "DoricNavBarDelegate.h"
#import "DoricViewController.h"
#import "DoricPromise.h"
#import "DoricLibrary.h"
#import "DoricNativePlugin.h"

View File

@@ -0,0 +1,65 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricContext.h
// Doric
//
// Created by pengfei.zhou on 2019/7/25.
//
#import <Foundation/Foundation.h>
#import "DoricDriver.h"
#import "DoricNavigatorDelegate.h"
#import "DoricNavBarDelegate.h"
NS_ASSUME_NONNULL_BEGIN
@class DoricViewNode;
@class DoricRootNode;
@interface DoricContext : NSObject
@property(nonatomic, weak) id <DoricNavigatorDelegate> navigator;
@property(nonatomic, weak) id <DoricNavBarDelegate> navBar;
@property(nonatomic, strong) NSString *contextId;
@property(nonatomic, strong) DoricDriver *driver;
@property(nonatomic, strong) NSMutableDictionary *pluginInstanceMap;
@property(nonatomic, strong) NSString *source;
@property(nonatomic, strong) NSString *script;;
@property(nonatomic, strong) NSMutableDictionary *initialParams;
@property(nonatomic, strong) DoricRootNode *rootNode;
@property(nonatomic, strong) NSMutableDictionary <NSString *, DoricViewNode *> *headNodes;
@property(nonatomic, copy) NSString *extra;
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source extra:(NSString *)extra;
- (DoricAsyncResult *)callEntity:(NSString *)method, ...;
- (DoricAsyncResult *)callEntity:(NSString *)method withArguments:(va_list)args;
- (DoricAsyncResult *)callEntity:(NSString *)method withArgumentsArray:(NSArray *)args;
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height;
- (void)reload:(NSString *)script;
- (void)onShow;
- (void)onHidden;
- (DoricViewNode *)targetViewNode:(NSString *)viewId;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,101 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricContext.m
// Doric
//
// Created by pengfei.zhou on 2019/7/25.
//
#import "DoricContext.h"
#import "DoricContextManager.h"
#import "DoricRootNode.h"
#import "DoricConstant.h"
#import "DoricExtensions.h"
@implementation DoricContext
- (instancetype)initWithScript:(NSString *)script source:(NSString *)source extra:(NSString *)extra {
if (self = [super init]) {
_driver = [DoricDriver instance];
_pluginInstanceMap = [NSMutableDictionary new];
[[DoricContextManager instance] createContext:self script:script source:source];
_headNodes = [NSMutableDictionary new];
DoricRootNode *rootNode = [[DoricRootNode alloc] initWithContext:self];
_rootNode = rootNode;
_script = script;
_source = source;
_initialParams = [@{@"width": @(0), @"height": @(0)} mutableCopy];
_extra = extra;
[self callEntity:DORIC_ENTITY_CREATE, nil];
}
return self;
}
- (DoricViewNode *)targetViewNode:(NSString *)viewId {
if ([self.rootNode.viewId isEqualToString:viewId]) {
return self.rootNode;
} else {
return self.headNodes[viewId];
}
}
- (void)dealloc {
[self callEntity:DORIC_ENTITY_DESTROY, nil];
[[DoricContextManager instance] destroyContext:self];
}
- (DoricAsyncResult *)callEntity:(NSString *)method, ... {
va_list args;
va_start(args, method);
DoricAsyncResult *ret = [self.driver invokeContextEntity:self.contextId method:method arguments:args];
va_end(args);
return ret;
}
- (DoricAsyncResult *)callEntity:(NSString *)method withArguments:(va_list)args {
return [self.driver invokeContextEntity:self.contextId method:method arguments:args];
}
- (DoricAsyncResult *)callEntity:(NSString *)method withArgumentsArray:(NSArray *)args {
return [self.driver invokeContextEntity:self.contextId method:method argumentsArray:args];
}
- (void)initContextWithWidth:(CGFloat)width height:(CGFloat)height {
[self.initialParams also:^(NSMutableDictionary *it) {
it[@"width"] = @(width);
it[@"height"] = @(height);
}];
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, self.extra, nil];
}
- (void)reload:(NSString *)script {
self.rootNode.viewId = nil;
self.script = script;
[self.driver createContext:self.contextId script:script source:self.source];
[self callEntity:DORIC_ENTITY_INIT, self.initialParams, nil];
[self onShow];
}
- (void)onShow {
[self callEntity:DORIC_ENTITY_SHOW, nil];
}
- (void)onHidden {
[self callEntity:DORIC_ENTITY_HIDDEN, nil];
}
@end

View File

@@ -0,0 +1,35 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricComponent.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricContext.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricContextHolder : NSObject
@property(nonatomic, weak) DoricContext *doricContext;
- (instancetype)initWithContext:(DoricContext *)doricContext;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,34 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricComponent.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricContextHolder.h"
@implementation DoricContextHolder
- (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [self init]) {
_doricContext = doricContext;
}
return self;
}
@end

View File

@@ -0,0 +1,40 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricContextManager.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricContext.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricContextManager : NSObject
+ (instancetype)instance;
- (void)createContext:(DoricContext *)context script:(NSString *)script source:(NSString *)source;
- (void)destroyContext:(DoricContext *)context;
- (DoricContext *)getContext:(NSString *)contextId;
- (NSArray *)aliveContexts;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,84 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricContextManager.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricContextManager.h"
#import "DoricContext.h"
@interface DoricContextManager ()
@property(nonatomic) NSInteger counter;
@property(nonatomic, strong) NSMutableDictionary *doricContextMap;
@property(nonatomic, strong) dispatch_queue_t mapQueue;
@end
@implementation DoricContextManager
- (instancetype)init {
if (self = [super init]) {
_doricContextMap = [[NSMutableDictionary alloc] init];
_counter = 0;
_mapQueue = dispatch_queue_create("doric.contextmap", DISPATCH_QUEUE_SERIAL);
}
return self;
}
+ (instancetype)instance {
static DoricContextManager *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[DoricContextManager alloc] init];
});
return _instance;
}
- (void)createContext:(DoricContext *)context script:(NSString *)script source:(NSString *)source {
context.contextId = [NSString stringWithFormat:@"%ld", (long) ++self.counter];
[context.driver createContext:context.contextId script:script source:source];
dispatch_sync(self.mapQueue, ^() {
NSValue *value = [NSValue valueWithNonretainedObject:context];
[self.doricContextMap setValue:value forKey:context.contextId];
});
}
- (DoricContext *)getContext:(NSString *)contextId {
__block DoricContext *context;
dispatch_sync(self.mapQueue, ^{
NSValue *value = [self.doricContextMap valueForKey:contextId];
context = value.nonretainedObjectValue;
});
return context;
}
- (void)destroyContext:(DoricContext *)context {
NSString *contextId = context.contextId;
[context.driver destroyContext:contextId].finishCallback = ^{
dispatch_sync(self.mapQueue, ^() {
[self.doricContextMap removeObjectForKey:contextId];
});
};
}
- (NSArray *)aliveContexts {
return [self.doricContextMap allValues];
}
@end

View File

@@ -0,0 +1,59 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricDriver.h
// Doric
//
// Created by pengfei.zhou on 2019/7/26.
//
#import <Foundation/Foundation.h>
#import "DoricAsyncResult.h"
#import "DoricRegistry.h"
typedef NS_ENUM(NSInteger, QueueMode) {
JS = 0,
UI,
INDEPENDENT
};
NS_ASSUME_NONNULL_BEGIN
@interface DoricDriver : NSObject
+ (instancetype)instance;
@property(nonatomic, strong) DoricRegistry *registry;
- (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source;
- (DoricAsyncResult *)destroyContext:(NSString *)contextId;
- (DoricAsyncResult *)invokeDoricMethod:(NSString *)method, ...;
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method, ...;
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method arguments:(va_list)args;
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method argumentsArray:(NSArray *)args;
- (void)connectDevKit:(NSString *)url;
- (void)disconnectDevKit;
- (void)ensureSyncInMainQueue:(dispatch_block_t)block;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,193 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricDriver.m
// Doric
//
// Created by pengfei.zhou on 2019/7/26.
//
#import "DoricDriver.h"
#import "DoricJSEngine.h"
#import "DoricConstant.h"
#import "DoricWSClient.h"
@interface DoricDriver ()
@property(nonatomic, strong) DoricJSEngine *jsExecutor;
@property(nonatomic, strong) DoricWSClient *wsclient;
@end
@implementation DoricDriver
@dynamic registry;
- (instancetype)init {
if (self = [super init]) {
_jsExecutor = [[DoricJSEngine alloc] init];
}
return self;
}
- (DoricRegistry *)registry {
return self.jsExecutor.registry;
}
+ (instancetype)instance {
static DoricDriver *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[DoricDriver alloc] init];
});
return _instance;
}
- (DoricAsyncResult<JSValue *> *)invokeDoricMethod:(NSString *)method, ... {
va_list args;
va_start(args, method);
DoricAsyncResult *ret = [self invokeDoricMethod:method arguments:args];
va_end(args);
return ret;
}
- (DoricAsyncResult<JSValue *> *)invokeDoricMethod:(NSString *)method arguments:(va_list)args {
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
id arg;
while ((arg = va_arg(args, id)) != nil) {
[array addObject:arg];
}
__weak typeof(self) _self = self;
dispatch_async(self.jsExecutor.jsQueue, ^() {
__strong typeof(_self) self = _self;
if (!self) return;
@try {
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:method argumentsArray:array];
[ret setupResult:jsValue];
} @catch (NSException *exception) {
[ret setupError:exception];
}
});
return ret;
}
- (DoricAsyncResult<JSValue *> *)invokeContextEntity:(NSString *)contextId method:(NSString *)method, ... {
va_list args;
va_start(args, method);
DoricAsyncResult *ret = [self invokeContextEntity:contextId method:method arguments:args];
va_end(args);
return ret;
}
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method arguments:(va_list)args {
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:contextId];
[array addObject:method];
id arg = va_arg(args, id);
while (arg != nil) {
[array addObject:arg];
arg = va_arg(args, JSValue *);
}
__weak typeof(self) _self = self;
dispatch_async(self.jsExecutor.jsQueue, ^() {
__strong typeof(_self) self = _self;
if (!self) return;
@try {
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:DORIC_CONTEXT_INVOKE argumentsArray:array];
[ret setupResult:jsValue];
} @catch (NSException *exception) {
[ret setupError:exception];
}
});
return ret;
}
- (DoricAsyncResult *)invokeContextEntity:(NSString *)contextId method:(NSString *)method argumentsArray:(NSArray *)args {
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
NSMutableArray *array = [[NSMutableArray alloc] init];
[array addObject:contextId];
[array addObject:method];
for (id arg in args) {
[array addObject:arg];
}
__weak typeof(self) _self = self;
dispatch_async(self.jsExecutor.jsQueue, ^() {
__strong typeof(_self) self = _self;
if (!self) return;
@try {
JSValue *jsValue = [self.jsExecutor invokeDoricMethod:DORIC_CONTEXT_INVOKE argumentsArray:array];
[ret setupResult:jsValue];
} @catch (NSException *exception) {
[ret setupError:exception];
}
});
return ret;
}
- (DoricAsyncResult *)createContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source {
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
__weak typeof(self) _self = self;
dispatch_async(self.jsExecutor.jsQueue, ^() {
__strong typeof(_self) self = _self;
if (!self) return;
@try {
[self.jsExecutor prepareContext:contextId script:script source:source];
[ret setupResult:[NSNumber numberWithBool:YES]];
} @catch (NSException *exception) {
[ret setupError:exception];
}
});
return ret;
}
- (DoricAsyncResult *)destroyContext:(NSString *)contextId {
DoricAsyncResult *ret = [[DoricAsyncResult alloc] init];
__weak typeof(self) _self = self;
dispatch_async(self.jsExecutor.jsQueue, ^() {
__strong typeof(_self) self = _self;
if (!self) return;
@try {
[self.jsExecutor destroyContext:contextId];
[ret setupResult:[NSNumber numberWithBool:YES]];
} @catch (NSException *exception) {
[ret setupError:exception];
}
});
return ret;
}
- (void)connectDevKit:(NSString *)url {
if (self.wsclient) {
[self.wsclient close];
}
self.wsclient = [[DoricWSClient alloc] initWithUrl:url];
}
- (void)disconnectDevKit {
if (self.wsclient) {
[self.wsclient close];
self.wsclient = nil;
}
}
- (void)ensureSyncInMainQueue:(dispatch_block_t)block {
if (strcmp(dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL), dispatch_queue_get_label(dispatch_get_main_queue())) == 0) {
block();
} else {
dispatch_async(dispatch_get_main_queue(), block);
}
}
@end

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/11.
//
#import <Foundation/Foundation.h>
#import "DoricRegistry.h"
@interface DoricLibrary : NSObject
- (void)load:(DoricRegistry *)registry;
@end

View File

@@ -0,0 +1,26 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/12/11.
//
#import "DoricLibrary.h"
@implementation DoricLibrary
- (void)load:(DoricRegistry *)registry {
}
@end

View File

@@ -0,0 +1,29 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricContext.h"
#import "DoricNavigatorDelegate.h"
@interface DoricPanel : UIViewController
@property(nonatomic, strong) DoricContext *doricContext;
- (void)config:(NSString *)script alias:(NSString *)alias extra:(NSString *)extra;
@end

View File

@@ -0,0 +1,54 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricPanel.h"
#import "Doric.h"
@implementation DoricPanel
- (void)config:(NSString *)script alias:(NSString *)alias extra:(NSString *)extra {
self.doricContext = [[[DoricContext alloc] initWithScript:script source:alias extra:extra] also:^(DoricContext *it) {
[it.rootNode setupRootView:[[DoricStackView new] also:^(DoricStackView *it) {
[self.view addSubview:it];
}]];
}];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.doricContext.rootNode.view also:^(DoricStackView *it) {
if (it.width != self.view.width || it.height != self.view.height) {
it.width = self.view.width;
it.height = self.view.height;
[self.doricContext initContextWithWidth:it.width height:it.height];
}
}];
}
- (void)viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.doricContext onShow];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.doricContext onHidden];
}
@end

View File

@@ -0,0 +1,46 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricRegistry.h
// Doric
//
// Created by pengfei.zhou on 2019/7/27.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@class DoricLibrary;
@interface DoricRegistry : NSObject
- (NSString *)acquireJSBundle:(NSString *)name;
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name;
- (void)registerNativePlugin:(Class)pluginClass withName:(NSString *)name;
- (Class)acquireNativePlugin:(NSString *)name;
- (void)registerViewNode:(Class)nodeClass withName:(NSString *)name;
- (Class)acquireViewNode:(NSString *)name;
+ (void)register:(DoricLibrary *)library;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,153 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricRegistry.m
// Doric
//
// Created by pengfei.zhou on 2019/7/27.
//
#import "DoricRegistry.h"
#import "DoricModalPlugin.h"
#import "DoricNetworkPlugin.h"
#import "DoricShaderPlugin.h"
#import "DoricStackNode.h"
#import "DoricVLayoutNode.h"
#import "DoricHLayoutNode.h"
#import "DoricTextNode.h"
#import "DoricImageNode.h"
#import "DoricListNode.h"
#import "DoricListItemNode.h"
#import "DoricScrollerNode.h"
#import "DoricSliderNode.h"
#import "DoricSlideItemNode.h"
#import "DoricStoragePlugin.h"
#import "DoricNavigatorPlugin.h"
#import "DoricNavBarPlugin.h"
#import "DoricRefreshableNode.h"
#import "DoricFlowLayoutItemNode.h"
#import "DoricFlowLayoutNode.h"
#import "DoricPopoverPlugin.h"
#import "DoricAnimatePlugin.h"
#import "DoricNestedSliderNode.h"
#import "DoricInputNode.h"
#import "DoricLibrary.h"
@interface DoricLibraries : NSObject
@property(nonatomic, strong) NSMutableSet <DoricLibrary *> *libraries;
+ (instancetype)instance;
@end
@implementation DoricLibraries
- (instancetype)init {
if (self = [super init]) {
_libraries = [NSMutableSet new];
}
return self;
}
+ (instancetype)instance {
static DoricLibraries *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [[DoricLibraries alloc] init];
});
return _instance;
}
@end
@interface DoricRegistry ()
@property(nonatomic, strong) NSMutableDictionary *bundles;
@property(nonatomic, strong) NSMutableDictionary *plugins;
@property(nonatomic, strong) NSMutableDictionary *nodes;
@end
@implementation DoricRegistry
+ (void)register:(DoricLibrary *)library {
[DoricLibraries.instance.libraries addObject:library];
}
- (instancetype)init {
if (self = [super init]) {
_bundles = [[NSMutableDictionary alloc] init];
_plugins = [[NSMutableDictionary alloc] init];
_nodes = [[NSMutableDictionary alloc] init];
[self innerRegister];
[DoricLibraries.instance.libraries enumerateObjectsUsingBlock:^(DoricLibrary *obj, BOOL *stop) {
[obj load:self];
}];
}
return self;
}
- (void)innerRegister {
[self registerNativePlugin:DoricShaderPlugin.class withName:@"shader"];
[self registerNativePlugin:DoricModalPlugin.class withName:@"modal"];
[self registerNativePlugin:DoricNetworkPlugin.class withName:@"network"];
[self registerNativePlugin:DoricStoragePlugin.class withName:@"storage"];
[self registerNativePlugin:DoricNavigatorPlugin.class withName:@"navigator"];
[self registerNativePlugin:DoricNavBarPlugin.class withName:@"navbar"];
[self registerNativePlugin:DoricPopoverPlugin.class withName:@"popover"];
[self registerNativePlugin:DoricAnimatePlugin.class withName:@"animate"];
[self registerViewNode:DoricStackNode.class withName:@"Stack"];
[self registerViewNode:DoricVLayoutNode.class withName:@"VLayout"];
[self registerViewNode:DoricHLayoutNode.class withName:@"HLayout"];
[self registerViewNode:DoricTextNode.class withName:@"Text"];
[self registerViewNode:DoricImageNode.class withName:@"Image"];
[self registerViewNode:DoricListNode.class withName:@"List"];
[self registerViewNode:DoricListItemNode.class withName:@"ListItem"];
[self registerViewNode:DoricScrollerNode.class withName:@"Scroller"];
[self registerViewNode:DoricSliderNode.class withName:@"Slider"];
[self registerViewNode:DoricSlideItemNode.class withName:@"SlideItem"];
[self registerViewNode:DoricRefreshableNode.class withName:@"Refreshable"];
[self registerViewNode:DoricFlowLayoutItemNode.class withName:@"FlowLayoutItem"];
[self registerViewNode:DoricFlowLayoutNode.class withName:@"FlowLayout"];
[self registerViewNode:DoricNestedSliderNode.class withName:@"NestedSlider"];
[self registerViewNode:DoricInputNode.class withName:@"Input"];
}
- (void)registerJSBundle:(NSString *)bundle withName:(NSString *)name {
self.bundles[name] = bundle;
}
- (NSString *)acquireJSBundle:(NSString *)name {
return self.bundles[name];
}
- (void)registerNativePlugin:(Class)pluginClass withName:(NSString *)name {
self.plugins[name] = pluginClass;
}
- (Class)acquireNativePlugin:(NSString *)name {
return self.plugins[name];
}
- (void)registerViewNode:(Class)nodeClass withName:(NSString *)name {
self.nodes[name] = nodeClass;
}
- (Class)acquireViewNode:(NSString *)name {
return self.nodes[name];
}
@end

View File

@@ -0,0 +1,26 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed onO an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricNavigatorDelegate.h"
#import "DoricNavBarDelegate.h"
@interface DoricViewController : UIViewController <DoricNavigatorDelegate, DoricNavBarDelegate>
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias extra:(NSString *)extra;
@end

View File

@@ -0,0 +1,107 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricViewController.h"
#import "DoricAsyncResult.h"
#import "DoricJSLoaderManager.h"
#import "DoricPanel.h"
#import "UIView+Doric.h"
#import "DoricExtensions.h"
#import "DoricUtil.h"
@interface DoricViewController ()
@property(nonatomic, strong) DoricPanel *doricPanel;
@property(nonatomic) BOOL navBarHidden;
@property(nonatomic, strong) UIImage *navBarImage;
@end
@implementation DoricViewController
- (instancetype)initWithScheme:(NSString *)scheme alias:(NSString *)alias extra:(NSString *)extra {
if (self = [super init]) {
self.edgesForExtendedLayout = UIRectEdgeNone;
DoricAsyncResult <NSString *> *result = [DoricJSLoaderManager.instance request:scheme];
result.resultCallback = ^(NSString *result) {
dispatch_async(dispatch_get_main_queue(), ^{
DoricPanel *panel = [DoricPanel new];
[panel.view also:^(UIView *it) {
it.backgroundColor = [UIColor whiteColor];
it.width = self.view.width;
it.height = self.view.height;
}];
[self.view addSubview:panel.view];
[self addChildViewController:panel];
[panel config:result alias:alias extra:extra];
panel.doricContext.navigator = self;
panel.doricContext.navBar = self;
self.doricPanel = panel;
});
};
}
return self;
}
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.navBarHidden = self.navigationController.navigationBarHidden;
self.navBarImage = [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault];
}
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];
if (self.navigationController.navigationBarHidden != self.navBarHidden) {
[self.navigationController setNavigationBarHidden:self.navBarHidden];
}
if (self.navBarImage != [self.navigationController.navigationBar backgroundImageForBarMetrics:UIBarMetricsDefault]) {
[self.navigationController.navigationBar setBackgroundImage:self.navBarImage forBarMetrics:UIBarMetricsDefault];
}
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
self.doricPanel.view.width = self.view.width;
self.doricPanel.view.height = self.view.height;
}
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated extra:(NSString *)extra {
DoricViewController *viewController = [[DoricViewController alloc] initWithScheme:scheme alias:alias extra:extra];
[self.navigationController pushViewController:viewController animated:animated];
}
- (void)doric_navigator_pop:(BOOL)animated {
[self.navigationController popViewControllerAnimated:animated];
}
- (BOOL)doric_navBar_isHidden {
return self.navigationController.navigationBarHidden;
}
- (void)doric_navBar_setHidden:(BOOL)hidden {
[self.navigationController setNavigationBarHidden:hidden];
}
- (void)doric_navBar_setTitle:(NSString *)title {
self.title = title;
}
- (void)doric_navBar_setBackgroundColor:(UIColor *)color {
[self.navigationController.navigationBar setBackgroundImage:UIImageWithColor(color) forBarMetrics:UIBarMetricsDefault];
}
@end

View File

@@ -0,0 +1,32 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSCoreExecutor.h
// Doric
//
// Created by pengfei.zhou on 2019/7/25.
//
#import <Foundation/Foundation.h>
#import "DoricJSExecutorProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricJSCoreExecutor : NSObject <DoricJSExecutorProtocol>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,64 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSCoreExecutor.m
// Doric
//
// Created by pengfei.zhou on 2019/7/25.
//
#import "DoricJSCoreExecutor.h"
@interface DoricJSCoreExecutor ()
@property(nonatomic, strong) JSContext *jsContext;
@end
@implementation DoricJSCoreExecutor
- (instancetype)init {
if (self = [super init]) {
_jsContext = [[JSContext alloc] init];
}
return self;
}
- (void)checkJSException {
if (self.jsContext.exception) {
NSString *errMsg = [NSString stringWithFormat:@"%@ (line %@ in the generated bundle)\n/***StackTrace***/\n%@/***StackTrace***/", self.jsContext.exception, self.jsContext.exception[@"line"], self.jsContext.exception[@"stack"]];
@throw [[NSException alloc] initWithName:@"DoricJS" reason:errMsg userInfo:nil];
}
}
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source {
NSString *ret = [[self.jsContext evaluateScript:script withSourceURL:[NSURL URLWithString:source]] toString];
[self checkJSException];
return ret;
}
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj {
self.jsContext[name] = obj;
[self checkJSException];
}
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args {
JSValue *obj = [self.jsContext objectForKeyedSubscript:objName];
JSValue *ret = [obj invokeMethod:funcName withArguments:args];
[self checkJSException];
return ret;
}
@end

View File

@@ -0,0 +1,46 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSEngine.h
// Doric
//
// Created by pengfei.zhou on 2019/7/26.
//
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
#import "DoricRegistry.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricJSEngine : NSObject
@property(nonatomic, strong) dispatch_queue_t jsQueue;
@property(nonatomic, strong) DoricRegistry *registry;
- (void)prepareContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source;
- (void)destroyContext:(NSString *)contextId;
- (JSValue *)invokeDoricMethod:(NSString *)method, ...;
- (JSValue *)invokeDoricMethod:(NSString *)method arguments:(va_list)args;
- (JSValue *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArray *)args;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,189 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSEngine.m
// Doric
//
// Created by pengfei.zhou on 2019/7/26.
//
#import "DoricJSEngine.h"
#import "DoricJSExecutorProtocol.h"
#import "DoricJSCoreExecutor.h"
#import "DoricJSRemoteExecutor.h"
#import "DoricConstant.h"
#import "DoricUtil.h"
#import "DoricBridgeExtension.h"
@interface DoricJSEngine ()
@property(nonatomic, strong) id <DoricJSExecutorProtocol> jsExecutor;
@property(nonatomic, strong) NSMutableDictionary *timers;
@property(nonatomic, strong) DoricBridgeExtension *bridgeExtension;
@end
@implementation DoricJSEngine
- (instancetype)init {
if (self = [super init]) {
_jsQueue = dispatch_queue_create("doric.jsengine", DISPATCH_QUEUE_SERIAL);
_bridgeExtension = [[DoricBridgeExtension alloc] init];
dispatch_async(_jsQueue, ^() {
self.timers = [[NSMutableDictionary alloc] init];
// Debug:
// self.jsExecutor = [[DoricJSRemoteExecutor alloc] init];
self.jsExecutor = [DoricJSCoreExecutor new];
self.registry = [[DoricRegistry alloc] init];
[self initJSExecutor];
[self initDoricEnvironment];
});
}
return self;
}
- (void)initJSExecutor {
__weak typeof(self) _self = self;
NSDictionary *infoDictionary = [[NSBundle mainBundle] infoDictionary];
[self.jsExecutor injectGlobalJSObject:INJECT_ENVIRONMENT obj:@{
@"platform": @"iOS",
@"platformVersion": [[UIDevice currentDevice] systemVersion],
@"appName": infoDictionary[@"CFBundleName"],
@"appVersion": infoDictionary[@"CFBundleShortVersionString"],
@"screenWidth": @([[UIScreen mainScreen] bounds].size.width),
@"screenHeight": @([[UIScreen mainScreen] bounds].size.height),
}];
[self.jsExecutor injectGlobalJSObject:INJECT_LOG obj:^(NSString *type, NSString *message) {
DoricLog(@"JS:%@", message);
}];
[self.jsExecutor injectGlobalJSObject:INJECT_EMPTY obj:^() {
}];
[self.jsExecutor injectGlobalJSObject:INJECT_REQUIRE obj:^(NSString *name) {
__strong typeof(_self) self = _self;
if (!self) return NO;
NSString *content = [self.registry acquireJSBundle:name];
if (!content) {
DoricLog(@"require js bundle:%@ is empty", name);
return NO;
}
@try {
[self.jsExecutor loadJSScript:[self packageModuleScript:name content:content]
source:[@"Module://" stringByAppendingString:name]];
} @catch (NSException *e) {
DoricLog(@"require js bundle:%@ error,for %@", name, e.reason);
}
return YES;
}];
[self.jsExecutor injectGlobalJSObject:INJECT_TIMER_SET
obj:^(NSNumber *timerId, NSNumber *interval, NSNumber *isInterval) {
__strong typeof(_self) self = _self;
NSString *timerId_str = [timerId stringValue];
BOOL repeat = [isInterval boolValue];
NSTimer *timer = [NSTimer timerWithTimeInterval:[interval doubleValue] / 1000 target:self selector:@selector(callbackTimer:) userInfo:@{@"timerId": timerId, @"repeat": isInterval} repeats:repeat];
[self.timers setValue:timer forKey:timerId_str];
dispatch_async(dispatch_get_main_queue(), ^() {
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
});
}];
[self.jsExecutor injectGlobalJSObject:INJECT_TIMER_CLEAR
obj:^(NSString *timerId) {
__strong typeof(_self) self = _self;
NSTimer *timer = [self.timers valueForKey:timerId];
if (timer) {
[timer invalidate];
[self.timers removeObjectForKey:timerId];
}
}];
[self.jsExecutor injectGlobalJSObject:INJECT_BRIDGE obj:^(NSString *contextId, NSString *module, NSString *method, NSString *callbackId, id argument) {
return [self.bridgeExtension callNativeWithContextId:contextId module:module method:method callbackId:callbackId argument:argument];
}];
}
- (void)initDoricEnvironment {
[self loadBuiltinJS:DORIC_BUNDLE_SANDBOX];
NSString *path = [DoricBundle() pathForResource:DORIC_BUNDLE_LIB ofType:@"js" inDirectory:@"bundle"];
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self.jsExecutor loadJSScript:[self packageModuleScript:DORIC_MODULE_LIB content:jsContent]
source:[@"Module://" stringByAppendingString:DORIC_MODULE_LIB]];
}
- (void)loadBuiltinJS:(NSString *)fileName {
NSString *path = [DoricBundle() pathForResource:DORIC_BUNDLE_SANDBOX ofType:@"js" inDirectory:@"bundle"];
NSString *jsContent = [NSString stringWithContentsOfFile:path encoding:NSUTF8StringEncoding error:nil];
[self.jsExecutor loadJSScript:jsContent source:[@"Assets://" stringByAppendingString:fileName]];
}
- (JSValue *)invokeDoricMethod:(NSString *)method, ... {
va_list args;
va_start(args, method);
JSValue *ret = [self invokeDoricMethod:method arguments:args];
va_end(args);
return ret;
}
- (JSValue *)invokeDoricMethod:(NSString *)method arguments:(va_list)args {
NSMutableArray *array = [[NSMutableArray alloc] init];
id arg = va_arg(args, id);
while (arg != nil) {
[array addObject:arg];
arg = va_arg(args, JSValue *);
}
return [self.jsExecutor invokeObject:GLOBAL_DORIC method:method args:array];
}
- (JSValue *)invokeDoricMethod:(NSString *)method argumentsArray:(NSArray *)args {
return [self.jsExecutor invokeObject:GLOBAL_DORIC method:method args:args];
}
- (NSString *)packageContextScript:(NSString *)contextId content:(NSString *)content {
NSString *ret = [NSString stringWithFormat:TEMPLATE_CONTEXT_CREATE, content, contextId, contextId, contextId];
return ret;
}
- (NSString *)packageModuleScript:(NSString *)moduleName content:(NSString *)content {
NSString *ret = [NSString stringWithFormat:TEMPLATE_MODULE, moduleName, content];
return ret;
}
- (void)prepareContext:(NSString *)contextId script:(NSString *)script source:(NSString *)source {
[self.jsExecutor loadJSScript:[self packageContextScript:contextId content:script]
source:[@"Context://" stringByAppendingString:source]];
}
- (void)destroyContext:(NSString *)contextId {
[self.jsExecutor loadJSScript:[NSString stringWithFormat:TEMPLATE_CONTEXT_DESTROY, contextId]
source:[@"_Context://" stringByAppendingString:contextId]];
}
- (void)callbackTimer:(NSTimer *)timer {
NSDictionary *userInfo = timer.userInfo;
NSNumber *timerId = [userInfo valueForKey:@"timerId"];
NSNumber *repeat = [userInfo valueForKey:@"repeat"];
__weak typeof(self) _self = self;
dispatch_async(self.jsQueue, ^() {
__strong typeof(_self) self = _self;
@try {
[self invokeDoricMethod:DORIC_TIMER_CALLBACK, timerId, nil];
} @catch (NSException *exception) {
DoricLog(@"Timer Callback error:%@", exception.reason);
}
if (![repeat boolValue]) {
[self.timers removeObjectForKey:[timerId stringValue]];
}
});
}
@end

View File

@@ -0,0 +1,38 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSEngineProtocal.h
// Doric
//
// Created by pengfei.zhou on 2019/7/25.
//
#import <Foundation/Foundation.h>
#import <JavaScriptCore/JavaScriptCore.h>
NS_ASSUME_NONNULL_BEGIN
@protocol DoricJSExecutorProtocol <NSObject>
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source;
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj;
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,35 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSRemoteExecutor.h
// Pods
//
// Created by 王劲鹏 on 2019/10/31.
//
#import <Foundation/Foundation.h>
#import "DoricJSExecutorProtocol.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricJSRemoteExecutor : NSObject <DoricJSExecutorProtocol>
@property(nonatomic, strong) dispatch_semaphore_t semaphore;
- (void)close;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,207 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSRemoteExecutor.m
// Doric
//
// Created by on 2019/10/31.
//
#import "DoricJSRemoteExecutor.h"
#import <SocketRocket/SRWebSocket.h>
#import "DoricUtil.h"
#import "DoricJSRemoteArgType.h"
#import "NSString+JsonString.h"
static NSString * const kUrlStr = @"ws://192.168.24.240:2080";
typedef id (^Block0)(void);
typedef id (^Block1)(id arg0);
typedef id (^Block2)(id arg0, id arg1);
typedef id (^Block3)(id arg0, id arg1, id arg2);
typedef id (^Block4)(id arg0, id arg1, id arg2, id arg3);
typedef id (^Block5)(id arg0, id arg1, id arg2, id arg3, id arg4);
@interface DoricJSRemoteExecutor () <SRWebSocketDelegate>
@property(nonatomic, strong) SRWebSocket *srWebSocket;
@property(nonatomic, strong) NSMutableDictionary <NSString *, id> *blockMDic;
@property(nonatomic, strong) JSValue *temp;
@end
@implementation DoricJSRemoteExecutor
- (instancetype)init {
if (self = [super init]) {
[self srWebSocket];
_semaphore = dispatch_semaphore_create(0);
DC_LOCK(self.semaphore);
}
return self;
}
#pragma mark - SRWebSocketDelegate
- (void)webSocketDidOpen:(SRWebSocket *)webSocket {
DoricLog(@"debugger webSocketDidOpen");
DC_UNLOCK(self.semaphore);
}
- (void)webSocket:(SRWebSocket *)webSocket didReceivePong:(NSData *)pongPayload {
DoricLog(@"debugger webSocketdidReceivePong");
}
- (void)webSocket:(SRWebSocket *)webSocket didReceiveMessage:(id)message {
NSData *jsonData = [message dataUsingEncoding:NSUTF8StringEncoding];
NSError *err;
NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:jsonData
options:NSJSONReadingMutableContainers
error:&err];
if (err) {
DoricLog(@"debugger webSocketdidReceiveMessage parse error%@", err);
return;
}
NSString *cmd = [[dic valueForKey:@"cmd"] copy];
if ([cmd isEqualToString:@"injectGlobalJSFunction"]) {
NSString *name = [dic valueForKey:@"name"];
NSArray *argsArr = [dic valueForKey:@"arguments"];
NSMutableArray *argsMarr = [NSMutableArray new];
for (NSUInteger i = 0; i < argsArr.count; i++) {
[argsMarr addObject:argsArr[i]];
}
id result;
id tmpBlk = self.blockMDic[name];
if (argsArr.count == 0) {
result = ((Block0) tmpBlk)();
} else if (argsArr.count == 1) {
result = ((Block1) tmpBlk)(argsArr[0]);
} else if (argsArr.count == 2) {
result = ((Block2)tmpBlk)(argsArr[0], argsArr[1]);
} else if (argsArr.count == 3) {
result = ((Block3)tmpBlk)(argsArr[0], argsArr[1], argsArr[2]);
} else if (argsArr.count == 4) {
result = ((Block4)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3]);
} else if (argsArr.count == 5) {
result = ((Block5)tmpBlk)(argsArr[0], argsArr[1], argsArr[2], argsArr[3], argsArr[4]);
}else {
DoricLog(@"error:args to more than 5. args:%@",argsArr);
}
} else if ([cmd isEqualToString:@"invokeMethod"]) {
@try {
self.temp = [JSValue valueWithObject:[dic valueForKey:@"result"] inContext:nil];
} @catch (NSException *exception) {
DoricLog(@"debugger ", NSStringFromSelector(_cmd), exception.reason);
} @finally {
DC_UNLOCK(self.semaphore);
}
}
}
- (void)webSocket:(SRWebSocket *)webSocket didFailWithError:(NSError *)error {
DoricLog(@"debugger webSocketdidFailWithError");
DC_UNLOCK(self.semaphore);
}
- (void)webSocket:(SRWebSocket *)webSocket didCloseWithCode:(NSInteger)code reason:(NSString *)reason wasClean:(BOOL)wasClean {
DoricLog(@"debugger webSocketdidCloseWithCode");
}
#pragma mark - DoricJSExecutorProtocol
- (NSString *)loadJSScript:(NSString *)script source:(NSString *)source {
return nil;
}
- (void)injectGlobalJSObject:(NSString *)name obj:(id)obj {
if ([obj isKindOfClass:NSClassFromString(@"NSBlock")]) {
self.blockMDic[name] = obj;
}
NSDictionary *jsonDic = @{
@"cmd": @"injectGlobalJSFunction",
@"name": name
};
NSString *jsonStr = [NSString dc_convertToJsonWithDic:jsonDic];
if (!jsonStr) {
return;
}
[self.srWebSocket send:jsonStr];
}
- (JSValue *)invokeObject:(NSString *)objName method:(NSString *)funcName args:(NSArray *)args {
NSMutableArray *argsMArr = [NSMutableArray new];
for (id arg in args) {
NSDictionary *dic = [self dicForArg:arg];
[argsMArr addObject:dic];
}
NSArray *argsArr = [argsMArr copy];
NSDictionary *jsonDic = @{
@"cmd": @"invokeMethod",
@"objectName": objName,
@"functionName": funcName,
@"javaValues": argsArr
};
NSString *jsonStr = [NSString dc_convertToJsonWithDic:jsonDic];
if (!jsonStr) {
return nil;
}
[self.srWebSocket send:jsonStr];
DC_LOCK(self.semaphore);
return self.temp;
}
- (NSDictionary *)dicForArg:(id)arg {
DoricJSRemoteArgType type = DoricargTypeWithArg(arg);
if (type == DoricJSRemoteArgTypeObject || type == DoricJSRemoteArgTypeArray) {
NSString *jsonStr = [NSString dc_convertToJsonWithDic:(NSDictionary *)arg];
arg = jsonStr;
}
NSDictionary *dic = @{
@"type": @(type),
@"value": arg
};
return dic;
}
- (void)close {
[self.srWebSocket close];
}
#pragma mark - Properties
- (SRWebSocket *)srWebSocket {
if (!_srWebSocket) {
NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:kUrlStr] cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData timeoutInterval:10];
_srWebSocket = [[SRWebSocket alloc] initWithURLRequest:request];
_srWebSocket.delegate = self;
[_srWebSocket open];
}
return _srWebSocket;
}
- (NSMutableDictionary *)blockMDic {
if (!_blockMDic) {
_blockMDic = [NSMutableDictionary new];
}
return _blockMDic;
}
@end

View File

@@ -0,0 +1,31 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricBridgeExtension.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface DoricBridgeExtension : NSObject
- (id)callNativeWithContextId:(NSString *)contextId module:(NSString *)module method:(NSString *)method callbackId:(NSString *)callbackId argument:(id)argument;
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,124 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricBridgeExtension.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricBridgeExtension.h"
#import "DoricRegistry.h"
#import "DoricContextManager.h"
#import "DoricNativePlugin.h"
#import "DoricUtil.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import <objc/runtime.h>
@implementation DoricBridgeExtension
- (id)callNativeWithContextId:(NSString *)contextId module:(NSString *)module method:(NSString *)method callbackId:(NSString *)callbackId argument:(id)argument {
DoricContext *context = [[DoricContextManager instance] getContext:contextId];
DoricRegistry *registry = context.driver.registry;
Class pluginClass = [registry acquireNativePlugin:module];
DoricNativePlugin *nativePlugin = context.pluginInstanceMap[module];
if (nativePlugin == nil) {
nativePlugin = [(DoricNativePlugin *) [pluginClass alloc] initWithContext:context];
context.pluginInstanceMap[module] = nativePlugin;
}
return [self findClass:pluginClass target:nativePlugin context:context method:method callbackId:callbackId argument:argument];
}
- (id)createParamWithMethodName:(NSString *)method context:(DoricContext *)context callbackId:(NSString *)callbackId argument:(id)argument {
if ([method isEqualToString:@"withPromise"]) {
return [[DoricPromise alloc] initWithContext:context callbackId:callbackId];
}
return argument;
}
- (id)findClass:(Class)clz target:(id)target context:(DoricContext *)context method:(NSString *)name callbackId:(NSString *)callbackId argument:(id)argument {
unsigned int count;
id ret = nil;
Method *methods = class_copyMethodList(clz, &count);
BOOL isFound = NO;
for (int i = 0; i < count; i++) {
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
NSArray *array = [methodName componentsSeparatedByString:@":"];
if (array && [array count] > 0) {
if ([array[0] isEqualToString:name]) {
isFound = YES;
SEL selector = NSSelectorFromString(methodName);
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
if (methodSignature) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = selector;
invocation.target = target;
__weak __typeof__(self) _self = self;
dispatch_block_t block = ^() {
__strong __typeof__(_self) self = _self;
@try {
NSMutableArray *tempArray = [NSMutableArray new];
for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) {
if (idx - 2 > [array count]) {
break;
}
id args = [self createParamWithMethodName:array[idx - 2] context:context callbackId:callbackId argument:argument];
if (args) {
[tempArray addObject:args];
}
[invocation setArgument:&args atIndex:idx];
}
[invocation invoke];
} @catch (NSException *exception) {
DoricLog(@"CallNative Error:%@", exception.reason);
}
};
const char *retType = methodSignature.methodReturnType;
if (!strcmp(retType, @encode(void))) {
ret = nil;
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), block);
} else if (!strcmp(retType, @encode(id))) {
void *retValue;
block();
[invocation getReturnValue:&retValue];
id returnValue = (__bridge id) retValue;
ret = [JSValue valueWithObject:[returnValue copy] inContext:[JSContext currentContext]];
} else {
DoricLog(@"CallNative Error:%@", @"Must return object type");
ret = nil;
}
}
break;
}
}
}
if (methods) {
free(methods);
}
if (!isFound) {
Class superclass = class_getSuperclass(clz);
if (superclass && superclass != [NSObject class]) {
return [self findClass:superclass target:target context:context method:name callbackId:callbackId argument:argument];
}
}
return ret;
}
@end

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricLoaderProtocol.h"
@interface DoricHttpJSLoader : NSObject <DoricLoaderProtocol>
@end

View File

@@ -0,0 +1,45 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricHttpJSLoader.h"
@implementation DoricHttpJSLoader
- (BOOL)filter:(NSString *)scheme {
return [scheme hasPrefix:@"http"];
}
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
DoricAsyncResult *ret = [DoricAsyncResult new];
NSURL *URL = [NSURL URLWithString:scheme];
NSURLRequest *request = [NSURLRequest requestWithURL:URL];
[[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
[ret setupResult:dataStr];
} else {
[ret setupError:[[NSException alloc] initWithName:@"DoricJSLoaderManager Exception" reason:error.description userInfo:nil]];
}
}] resume];
return ret;
}
@end

View File

@@ -0,0 +1,33 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSLoaderManager.h
// Doric
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricLoaderProtocol.h"
#import "DoricAsyncResult.h"
@interface DoricJSLoaderManager : NSObject
+ (instancetype)instance;
- (void)addJSLoader:(id <DoricLoaderProtocol>)loader;
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme;
@end

View File

@@ -0,0 +1,68 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricJSLoaderManager.m
// Doric
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricJSLoaderManager.h"
#import "DoricMainBundleJSLoader.h"
#import "DoricHttpJSLoader.h"
#import "Doric.h"
@interface DoricJSLoaderManager ()
@property(nonatomic, copy) NSSet <id <DoricLoaderProtocol>> *loaders;
@end
@implementation DoricJSLoaderManager
+ (instancetype)instance {
static DoricJSLoaderManager *_instance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
_instance = [DoricJSLoaderManager new];
});
return _instance;
}
- (instancetype)init {
if (self = [super init]) {
_loaders = [[NSSet alloc] initWithArray:@[
[DoricMainBundleJSLoader new],
[DoricHttpJSLoader new],
]];
}
return self;
}
- (void)addJSLoader:(id <DoricLoaderProtocol>)loader {
self.loaders = [[self.loaders mutableCopy] also:^(NSMutableSet *it) {
[it addObject:loader];
}];
}
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
__block DoricAsyncResult *ret;
[self.loaders enumerateObjectsUsingBlock:^(id <DoricLoaderProtocol> obj, BOOL *stop) {
if ([obj filter:scheme]) {
ret = [obj request:scheme];
*stop = YES;
}
}];
return ret;
}
@end

View File

@@ -0,0 +1,27 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricAsyncResult.h"
@protocol DoricLoaderProtocol <NSObject>
- (BOOL)filter:(NSString *)scheme;
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme;
@end

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricLoaderProtocol.h"
@interface DoricMainBundleJSLoader : NSObject <DoricLoaderProtocol>
@end

View File

@@ -0,0 +1,42 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricMainBundleJSLoader.h"
@implementation DoricMainBundleJSLoader
- (BOOL)filter:(NSString *)scheme {
return [scheme hasPrefix:@"assets"];
}
- (DoricAsyncResult <NSString *> *)request:(NSString *)scheme {
DoricAsyncResult <NSString *> *ret = [DoricAsyncResult new];
NSString *path = [[NSBundle mainBundle] bundlePath];
NSString *fullPath = [path stringByAppendingPathComponent:[scheme substringFromIndex:@"assets://".length]];
NSError *error;
NSString *jsContent = [NSString stringWithContentsOfFile:fullPath encoding:NSUTF8StringEncoding error:&error];
if (error) {
[ret setupError:[NSException new]];
} else {
[ret setupResult:jsContent];
}
return ret;
}
@end

View File

@@ -0,0 +1,31 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/25.
//
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@protocol DoricNavBarDelegate <NSObject>
- (BOOL)doric_navBar_isHidden;
- (void)doric_navBar_setHidden:(BOOL)hidden;
- (void)doric_navBar_setTitle:(NSString *)title;
- (void)doric_navBar_setBackgroundColor:(UIColor *)color;
@end

View File

@@ -0,0 +1,26 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
@protocol DoricNavigatorDelegate <NSObject>
- (void)doric_navigator_push:(NSString *)scheme alias:(NSString *)alias animated:(BOOL)animated extra:(NSString *)extra;
- (void)doric_navigator_pop:(BOOL)animated;
@end

View File

@@ -0,0 +1,10 @@
//
// Created by pengfei.zhou on 2019/11/29.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricAnimatePlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,33 @@
//
// Created by pengfei.zhou on 2019/11/29.
//
#import "DoricAnimatePlugin.h"
#import "DoricRootNode.h"
@implementation DoricAnimatePlugin
- (void)submit:(NSDictionary *)args withPromise:(DoricPromise *)promise {
[promise resolve:nil];
}
- (void)animateRender:(NSDictionary *)args withPromise:(DoricPromise *)promise {
NSNumber *duration = args[@"duration"];
dispatch_async(dispatch_get_main_queue(), ^{
NSString *viewId = args[@"id"];
[UIView animateWithDuration:[duration floatValue] / 1000
animations:^{
if (self.doricContext.rootNode.viewId == nil) {
self.doricContext.rootNode.viewId = viewId;
[self.doricContext.rootNode blend:args[@"props"]];
} else {
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
[viewNode blend:args[@"props"]];
}
}
completion:^(BOOL finished) {
[promise resolve:nil];
}];
});
}
@end

View File

@@ -0,0 +1,32 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricModalPlugin.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricModalPlugin : DoricNativePlugin
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,115 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricModalPlugin.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricModalPlugin.h"
#import "DoricUtil.h"
#import "DoricExtensions.h"
@implementation DoricModalPlugin
- (void)toast:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{
__block DoricGravity gravity = BOTTOM;
[dic[@"gravity"] also:^(NSNumber *it) {
gravity = (DoricGravity) [it integerValue];
}];
ShowToast(dic[@"msg"], gravity);
});
}
- (void)alert:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
message:dic[@"msg"]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *action = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"OK", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[promise resolve:nil];
}];
[alert addAction:action];
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
[vc presentViewController:alert animated:YES completion:nil];
});
}
- (void)confirm:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
message:dic[@"msg"]
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *okAction = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"Ok", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[promise resolve:nil];
}];
[alert addAction:okAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:dic[@"cancelLabel"] ?: NSLocalizedString(@"Cancel", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
[promise reject:nil];
}];
[alert addAction:cancelAction];
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
[vc presentViewController:alert animated:YES completion:nil];
});
}
- (void)prompt:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{
UIAlertController *alert = [UIAlertController alertControllerWithTitle:dic[@"title"]
message:dic[@"msg"]
preferredStyle:UIAlertControllerStyleAlert];
NSString *placeholder = dic[@"defaultText"];
NSString *preText = dic[@"text"];
[alert addTextFieldWithConfigurationHandler:^(UITextField *_Nonnull textField) {
if (placeholder.length > 0) {
textField.placeholder = placeholder;
}
if (preText.length > 0) {
textField.text = preText;
}
}];
__weak typeof(alert) _alert = alert;
UIAlertAction *okAction = [UIAlertAction actionWithTitle:dic[@"okLabel"] ?: NSLocalizedString(@"Ok", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
__strong typeof(_alert) alert = _alert;
[promise resolve:alert.textFields.lastObject.text];
}];
[alert addAction:okAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:dic[@"cancelLabel"] ?: NSLocalizedString(@"Cancel", nil)
style:UIAlertActionStyleDefault
handler:^(UIAlertAction *action) {
__strong typeof(_alert) alert = _alert;
[promise reject:alert.textFields.lastObject.text];
}];
[alert addAction:cancelAction];
UIViewController *vc = [UIApplication sharedApplication].keyWindow.rootViewController;
[vc presentViewController:alert animated:YES completion:nil];
});
}
@end

View File

@@ -0,0 +1,34 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricNativePlugin.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricContextHolder.h"
#import "DoricPromise.h"
#import "DoricRegistry.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricNativePlugin : DoricContextHolder
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,27 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricNativePlugin.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricNativePlugin.h"
@implementation DoricNativePlugin
@end

View File

@@ -0,0 +1,26 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/25.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricNavBarPlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,68 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/25.
//
#import "DoricNavBarPlugin.h"
#import "DoricUtil.h"
@implementation DoricNavBarPlugin
- (void)isHidden:(NSDictionary *)param withPromise:(DoricPromise *)promise {
if (self.doricContext.navBar) {
dispatch_async(dispatch_get_main_queue(), ^{
[promise resolve:@([self.doricContext.navBar doric_navBar_isHidden])];
});
} else {
[promise reject:@"Not implement NavBar"];
}
}
- (void)setHidden:(NSDictionary *)param withPromise:(DoricPromise *)promise {
if (self.doricContext.navBar) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.doricContext.navBar doric_navBar_setHidden:[param[@"hidden"] boolValue]];
[promise resolve:nil];
});
} else {
[promise reject:@"Not implement NavBar"];
}
}
- (void)setTitle:(NSDictionary *)param withPromise:(DoricPromise *)promise {
if (self.doricContext.navBar) {
dispatch_async(dispatch_get_main_queue(), ^{
[self.doricContext.navBar doric_navBar_setTitle:param[@"title"]];
[promise resolve:nil];
});
} else {
[promise reject:@"Not implement NavBar"];
}
}
- (void)setBgColor:(NSDictionary *)param withPromise:(DoricPromise *)promise {
if (self.doricContext.navBar) {
dispatch_async(dispatch_get_main_queue(), ^{
UIColor *color = DoricColor(param[@"color"]);
[self.doricContext.navBar doric_navBar_setBackgroundColor:color];
[promise resolve:nil];
});
} else {
[promise reject:@"Not implement NavBar"];
}
}
@end

View File

@@ -0,0 +1,24 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricNavigatorPlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,52 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/23.
//
#import "DoricNavigatorPlugin.h"
@implementation DoricNavigatorPlugin
- (void)push:(NSDictionary *)params {
dispatch_async(dispatch_get_main_queue(), ^{
BOOL animated = YES;
NSString *scheme = params[@"scheme"];
NSString *alias = scheme;
NSDictionary *config = params[@"config"];
if (config) {
if (config[@"animated"]) {
animated = [config[@"animated"] boolValue];
}
if (config[@"alias"]) {
alias = config[@"alias"];
}
}
[self.doricContext.navigator doric_navigator_push:scheme alias:alias animated:animated extra:config[@"extra"]];
});
}
- (void)pop:(NSDictionary *)params {
dispatch_async(dispatch_get_main_queue(), ^{
BOOL animated = YES;
if (params[@"animated"]) {
animated = [params[@"animated"] boolValue];
}
[self.doricContext.navigator doric_navigator_pop:animated];
});
}
@end

View File

@@ -0,0 +1,24 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/21.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricNetworkPlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,59 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/21.
//
#import "DoricNetworkPlugin.h"
@implementation DoricNetworkPlugin
- (void)request:(NSDictionary *)dic withPromise:(DoricPromise *)promise {
NSString *url = dic[@"url"];
NSString *method = dic[@"method"];
NSDictionary <NSString *, NSString *> *headers = dic[@"headers"];
NSNumber *timeout = dic[@"timeout"];
NSString *data = dic[@"data"];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[NSURL URLWithString:url]];
request.HTTPMethod = method.uppercaseString;
if (timeout) {
request.timeoutInterval = [timeout floatValue] / 1000;
}
if (headers) {
[headers enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *obj, BOOL *stop) {
[request setValue:obj forHTTPHeaderField:key];
}];
}
if (data) {
[request setHTTPBody:[data dataUsingEncoding:NSUTF8StringEncoding]];
}
[[[NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]
dataTaskWithRequest:request
completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
if (!error) {
NSString *dataStr = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
NSDictionary *resDic = @{
@"status": @(((NSHTTPURLResponse *) response).statusCode),
@"headers": ((NSHTTPURLResponse *) response).allHeaderFields,
@"data": dataStr,
};
[promise resolve:resDic];
} else {
[promise reject:error.description];
}
}] resume];
}
@end

View File

@@ -0,0 +1,9 @@
//
// Created by pengfei.zhou on 2019/11/28.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricPopoverPlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,70 @@
//
// Created by pengfei.zhou on 2019/11/28.
//
#import "DoricPopoverPlugin.h"
#import "DoricRootNode.h"
#import "Doric.h"
@interface DoricPopoverPlugin ()
@property(nonatomic, strong) UIView *fullScreenView;
@end
@implementation DoricPopoverPlugin
- (void)show:(NSDictionary *)params withPromise:(DoricPromise *)promise {
dispatch_async(dispatch_get_main_queue(), ^{
UIView *superView = [UIApplication sharedApplication].windows.lastObject;
if (!self.fullScreenView) {
self.fullScreenView = [[DoricStackView new] also:^(UIView *it) {
it.width = superView.width;
it.height = superView.height;
it.top = it.left = 0;
[superView addSubview:it];
}];
}
[superView bringSubviewToFront:self.fullScreenView];
self.fullScreenView.hidden = NO;
NSString *viewId = params[@"id"];
NSString *type = params[@"type"];
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
if (!viewNode) {
viewNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:nil];
it.view.layoutConfig = [DoricLayoutConfig new];
[self.fullScreenView addSubview:it.view];
self.doricContext.headNodes[viewId] = it;
}];
}
[viewNode blend:params[@"props"]];
[promise resolve:nil];
});
}
- (void)dismiss:(NSDictionary *)params withPromise:(DoricPromise *)promise {
NSString *viewId = params[@"id"];
dispatch_async(dispatch_get_main_queue(), ^{
if (viewId) {
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
[self dismissViewNode:viewNode];
} else {
[self dismissPopover];
}
[promise resolve:nil];
});
}
- (void)dismissViewNode:(DoricViewNode *)node {
[self.doricContext.headNodes removeObjectForKey:node.viewId];
[node.view removeFromSuperview];
if (self.doricContext.headNodes.count == 0) {
self.fullScreenView.hidden = YES;
}
}
- (void)dismissPopover {
for (DoricViewNode *node in self.doricContext.headNodes.allValues) {
[self dismissViewNode:node];
}
}
@end

View File

@@ -0,0 +1,32 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricPromise.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricContext.h"
@interface DoricPromise : NSObject
- (instancetype)initWithContext:(DoricContext *)context callbackId:(NSString *)callbackId;
- (void)resolve:(id)result;
- (void)reject:(id)result;
@end

View File

@@ -0,0 +1,49 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricPromise.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricPromise.h"
#import "DoricConstant.h"
@interface DoricPromise ()
@property(nonatomic, strong) DoricContext *context;
@property(nonatomic, strong) NSString *callbackId;
@end
@implementation DoricPromise
- (instancetype)initWithContext:(DoricContext *)context callbackId:(NSString *)callbackId {
if (self = [super init]) {
_context = context;
_callbackId = callbackId;
}
return self;
}
- (void)resolve:(id)result {
[self.context.driver invokeDoricMethod:DORIC_BRIDGE_RESOLVE, self.context.contextId, self.callbackId, result, nil];
}
- (void)reject:(id)result {
[self.context.driver invokeDoricMethod:DORIC_BRIDGE_REJECT, self.context.contextId, self.callbackId, result, nil];
}
@end

View File

@@ -0,0 +1,32 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricShaderPlugin.h
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricShaderPlugin : DoricNativePlugin
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,143 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricShaderPlugin.m
// Doric
//
// Created by pengfei.zhou on 2019/7/29.
//
#import "DoricShaderPlugin.h"
#import "DoricRootNode.h"
#import "DoricUtil.h"
#import <objc/runtime.h>
@implementation DoricShaderPlugin
- (void)render:(NSDictionary *)argument {
if (!argument) {
return;
}
__weak typeof(self) _self = self;
dispatch_async(dispatch_get_main_queue(), ^{
__strong typeof(_self) self = _self;
NSString *viewId = argument[@"id"];
if (self.doricContext.rootNode.viewId == nil) {
self.doricContext.rootNode.viewId = viewId;
[self.doricContext.rootNode blend:argument[@"props"]];
} else {
DoricViewNode *viewNode = [self.doricContext targetViewNode:viewId];
[viewNode blend:argument[@"props"]];
}
});
}
- (id)command:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
NSArray *viewIds = argument[@"viewIds"];
id args = argument[@"args"];
NSString *name = argument[@"name"];
DoricViewNode *viewNode = nil;
for (NSString *viewId in viewIds) {
if (!viewNode) {
viewNode = [self.doricContext targetViewNode:viewId];
} else {
if ([viewNode isKindOfClass:[DoricSuperNode class]]) {
viewNode = [((DoricSuperNode *) viewNode) subNodeWithViewId:viewId];
}
}
}
if (!viewNode) {
[promise reject:@"Cannot find opposite view"];
return nil;
} else {
return [self findClass:[viewNode class] target:viewNode method:name promise:promise argument:args];
}
}
- (id)createParamWithMethodName:(NSString *)method promise:(DoricPromise *)promise argument:(id)argument {
if ([method isEqualToString:@"withPromise"]) {
return promise;
}
return argument;
}
- (id)findClass:(Class)clz target:(id)target method:(NSString *)name promise:(DoricPromise *)promise argument:(id)argument {
unsigned int count;
id ret = nil;
Method *methods = class_copyMethodList(clz, &count);
BOOL isFound = NO;
for (int i = 0; i < count; i++) {
NSString *methodName = [NSString stringWithCString:sel_getName(method_getName(methods[i])) encoding:NSUTF8StringEncoding];
NSArray *array = [methodName componentsSeparatedByString:@":"];
if (array && [array count] > 0) {
if ([array[0] isEqualToString:name]) {
isFound = YES;
SEL selector = NSSelectorFromString(methodName);
NSMethodSignature *methodSignature = [target methodSignatureForSelector:selector];
if (methodSignature) {
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.selector = selector;
invocation.target = target;
__weak __typeof__(self) _self = self;
dispatch_block_t block = ^() {
__strong __typeof__(_self) self = _self;
@try {
for (NSUInteger idx = 2; idx < methodSignature.numberOfArguments; idx++) {
if (idx - 2 > [array count]) {
break;
}
id param = [self createParamWithMethodName:array[idx - 2] promise:promise argument:argument];
[invocation setArgument:&param atIndex:idx];
}
[invocation invoke];
} @catch (NSException *exception) {
DoricLog(@"CallNative Error:%@", exception.reason);
}
};
dispatch_async(dispatch_get_main_queue(), ^{
void *retValue;
block();
const char *retType = methodSignature.methodReturnType;
if (!strcmp(retType, @encode(void))) {
} else {
[invocation getReturnValue:&retValue];
id returnValue = (__bridge id) retValue;
[promise resolve:returnValue];
}
});
return ret;
}
break;
}
}
}
if (methods) {
free(methods);
}
if (!isFound) {
Class superclass = class_getSuperclass(clz);
if (superclass && superclass != [NSObject class]) {
return [self findClass:superclass target:target method:name promise:promise argument:argument];
}
}
return ret;
}
@end

View File

@@ -0,0 +1,24 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/22.
//
#import <Foundation/Foundation.h>
#import "DoricNativePlugin.h"
@interface DoricStoragePlugin : DoricNativePlugin
@end

View File

@@ -0,0 +1,98 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/22.
//
#import "DoricStoragePlugin.h"
#import "YYDiskCache.h"
static NSString *doric_prefix = @"pref";
@interface DoricStoragePlugin ()
@property(atomic, strong) NSMutableDictionary <NSString *, YYDiskCache *> *cachedMap;
@property(nonatomic, strong) YYDiskCache *defaultCache;
@property(nonatomic, copy) NSString *basePath;
@end
@implementation DoricStoragePlugin
- (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [super initWithContext:doricContext]) {
_basePath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject]
stringByAppendingPathComponent:@"doric"];
_cachedMap = [NSMutableDictionary new];
}
return self;
}
- (YYDiskCache *)defaultCache {
if (!_defaultCache) {
_defaultCache = [[YYDiskCache alloc] initWithPath:[self.basePath stringByAppendingPathComponent:doric_prefix]];
}
return _defaultCache;
}
- (YYDiskCache *)getDiskCache:(NSString *)zone {
YYDiskCache *diskCache;
if (zone) {
diskCache = self.cachedMap[zone];
if (!diskCache) {
diskCache = [[YYDiskCache alloc] initWithPath:[self.basePath
stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_%@", doric_prefix, zone]]];
self.cachedMap[zone] = diskCache;
}
} else {
diskCache = self.defaultCache;
}
return diskCache;
}
- (void)setItem:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
NSString *zone = argument[@"zone"];
NSString *key = argument[@"key"];
NSString *value = argument[@"value"];
YYDiskCache *diskCache = [self getDiskCache:zone];
[diskCache setObject:value forKey:key withBlock:^{
[promise resolve:nil];
}];
}
- (void)getItem:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
NSString *zone = argument[@"zone"];
NSString *key = argument[@"key"];
YYDiskCache *diskCache = [self getDiskCache:zone];
[diskCache objectForKey:key withBlock:^(NSString *key, NSString *value) {
[promise resolve:value];
}];
}
- (void)remove:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
NSString *zone = argument[@"zone"];
NSString *key = argument[@"key"];
YYDiskCache *diskCache = [self getDiskCache:zone];
[diskCache removeObjectForKey:key withBlock:^(NSString *key) {
[promise resolve:nil];
}];
}
- (void)clear:(NSDictionary *)argument withPromise:(DoricPromise *)promise {
NSString *zone = argument[@"zone"];
YYDiskCache *diskCache = [self getDiskCache:zone];
[diskCache removeAllObjectsWithBlock:^{
[promise resolve:nil];
}];
}
@end

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/26.
//
#import <Foundation/Foundation.h>
#import "DoricSuperNode.h"
#import "DoricSwipeRefreshLayout.h"
@interface DoricRefreshableNode : DoricSuperNode<DoricSwipeRefreshLayout *>
@end

View File

@@ -0,0 +1,176 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/26.
//
#import "DoricRefreshableNode.h"
#import "Doric.h"
@interface DoricRefreshableNode () <DoricSwipePullingDelegate>
@property(nonatomic, strong) DoricViewNode *contentNode;
@property(nonatomic, copy) NSString *contentViewId;
@property(nonatomic, strong) DoricViewNode *headerNode;
@property(nonatomic, copy) NSString *headerViewId;
@end
@implementation DoricRefreshableNode
- (DoricSwipeRefreshLayout *)build {
return [[DoricSwipeRefreshLayout new] also:^(DoricSwipeRefreshLayout *it) {
it.swipePullingDelegate = self;
}];
}
- (void)blendView:(DoricSwipeRefreshLayout *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"content" isEqualToString:name]) {
self.contentViewId = prop;
} else if ([@"header" isEqualToString:name]) {
self.headerViewId = prop;
} else if ([@"onRefresh" isEqualToString:name]) {
__weak typeof(self) _self = self;
NSString *funcId = prop;
self.view.onRefreshBlock = ^{
__strong typeof(_self) self = _self;
[self callJSResponse:funcId, nil];
};
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
if ([viewId isEqualToString:self.contentViewId]) {
return self.contentNode;
} else if ([viewId isEqualToString:self.headerViewId]) {
return self.headerNode;
} else {
return nil;
}
}
- (void)blend:(NSDictionary *)props {
[super blend:props];
[self blendContent];
[self blendHeader];
}
- (void)blendContent {
NSDictionary *contentModel = [self subModelOf:self.contentViewId];
if (!contentModel) {
return;
}
NSString *viewId = contentModel[@"id"];
NSString *type = contentModel[@"type"];
NSDictionary *childProps = contentModel[@"props"];
if (self.contentNode) {
if ([self.contentNode.viewId isEqualToString:viewId]) {
//skip
} else {
if (self.reusable && [type isEqualToString:self.contentNode.type]) {
[self.contentNode also:^(DoricViewNode *it) {
it.viewId = viewId;
[it blend:childProps];
}];
} else {
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
self.view.contentView = it.view;
}];
}
}
} else {
self.contentNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
self.view.contentView = it.view;
}];
}
}
- (void)blendHeader {
NSDictionary *headerModel = [self subModelOf:self.headerViewId];
if (!headerModel) {
return;
}
NSString *viewId = headerModel[@"id"];
NSString *type = headerModel[@"type"];
NSDictionary *childProps = headerModel[@"props"];
if (self.headerNode) {
if ([self.headerNode.viewId isEqualToString:viewId]) {
//skip
} else {
if (self.reusable && [type isEqualToString:self.headerNode.type]) {
[self.headerNode also:^(DoricViewNode *it) {
it.viewId = viewId;
[it blend:childProps];
}];
} else {
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
self.view.headerView = it.view;
}];
}
}
} else {
self.headerNode = [[DoricViewNode create:self.doricContext withType:type] also:^(DoricViewNode *it) {
it.viewId = viewId;
[it initWithSuperNode:self];
[it blend:childProps];
self.view.headerView = it.view;
}];
}
}
- (void)blendSubNode:(NSDictionary *)subModel {
[[self subNodeWithViewId:subModel[@"id"]] blend:subModel[@"props"]];
}
- (void)startAnimation {
[self.headerNode callJSResponse:@"startAnimation", nil];
}
- (void)stopAnimation {
[self.headerNode callJSResponse:@"stopAnimation", nil];
}
- (void)setPullingDistance:(CGFloat)distance {
[self.headerNode callJSResponse:@"setPullingDistance", @(distance), nil];
}
- (void)setRefreshing:(NSNumber *)refreshable withPromise:(DoricPromise *)promise {
self.view.refreshing = [refreshable boolValue];
[promise resolve:nil];
}
- (void)setRefreshable:(NSNumber *)refreshing withPromise:(DoricPromise *)promise {
self.view.refreshable = [refreshing boolValue];
[promise resolve:nil];
}
- (NSNumber *)isRefreshing {
return @(self.view.refreshing);
}
- (NSNumber *)isRefreshable {
return @(self.view.refreshable);
}
@end

View File

@@ -0,0 +1,22 @@
//
// Created by pengfei.zhou on 2019/11/26.
//
#import <Foundation/Foundation.h>
@protocol DoricSwipePullingDelegate <NSObject>
- (void)startAnimation;
- (void)stopAnimation;
- (void)setPullingDistance:(CGFloat)rotation;
@end
@interface DoricSwipeRefreshLayout : UIScrollView
@property(nonatomic, strong) UIView *contentView;
@property(nonatomic, strong) UIView *headerView;
@property(nonatomic, assign) BOOL refreshable;
@property(nonatomic, assign) BOOL refreshing;
@property(nonatomic, strong) void (^onRefreshBlock)(void);
@property(nonatomic, weak) id <DoricSwipePullingDelegate> swipePullingDelegate;
@end

View File

@@ -0,0 +1,159 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/26.
//
#import "DoricSwipeRefreshLayout.h"
#import "UIView+Doric.h"
#import "DoricLayouts.h"
#import "Doric.h"
@interface DoricSwipeRefreshLayout () <UIScrollViewDelegate>
@end
@implementation DoricSwipeRefreshLayout
- (instancetype)initWithFrame:(CGRect)frame {
if (self = [super initWithFrame:frame]) {
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
self.alwaysBounceVertical = YES;
self.delegate = self;
if (@available(iOS 11, *)) {
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
}
return self;
}
- (instancetype)init {
if (self = [super init]) {
self.showsHorizontalScrollIndicator = NO;
self.showsVerticalScrollIndicator = NO;
self.alwaysBounceVertical = YES;
self.delegate = self;
if (@available(iOS 11, *)) {
self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever;
}
}
return self;
}
- (CGSize)sizeThatFits:(CGSize)size {
if (self.contentView) {
return [self.contentView measureSize:size];
}
return CGSizeZero;
}
- (BOOL)requestFromSubview:(UIView *)subview {
if (subview == self.headerView) {
return NO;
}
return [super requestFromSubview:subview];
}
- (void)layoutSubviews {
[super layoutSubviews];
}
- (void)layoutSelf:(CGSize)targetSize {
if (self.contentOffset.y != 0) {
return;
}
self.width = targetSize.width;
self.height = targetSize.height;
[self.headerView also:^(UIView *it) {
[it layoutSelf:[it measureSize:targetSize]];
it.bottom = 0;
it.centerX = self.centerX;
}];
[self.contentView also:^(UIView *it) {
[it layoutSelf:targetSize];
}];
self.contentSize = self.frame.size;
}
- (void)setContentView:(UIView *)contentView {
if (_contentView) {
[_contentView removeFromSuperview];
}
_contentView = contentView;
[self addSubview:contentView];
}
- (void)setHeaderView:(UIView *)headerView {
if (_headerView) {
[_headerView removeFromSuperview];
}
_headerView = headerView;
[self addSubview:headerView];
self.refreshable = YES;
}
- (void)scrollViewDidEndDragging:(UIScrollView *)scrollView willDecelerate:(BOOL)decelerate {
if (-scrollView.contentOffset.y >= self.headerView.height) {
dispatch_async(dispatch_get_main_queue(), ^{
self.refreshing = YES;
});
}
}
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
if (scrollView.contentOffset.y <= 0) {
[self.swipePullingDelegate setPullingDistance:-scrollView.contentOffset.y];
}
}
- (void)setContentOffset:(CGPoint)contentOffset {
[super setContentOffset:contentOffset];
}
- (void)setRefreshing:(BOOL)refreshing {
if (_refreshing == refreshing) {
return;
}
if (refreshing) {
[self setContentOffset:CGPointMake(0, -self.headerView.height) animated:YES];
self.scrollEnabled = NO;
if (self.onRefreshBlock) {
self.onRefreshBlock();
}
} else {
[self setContentOffset:(CGPoint) {0, 0} animated:YES];
self.scrollEnabled = YES;
}
_refreshing = refreshing;
}
- (void)setRefreshable:(BOOL)refreshable {
self.scrollEnabled = refreshable;
if (refreshable) {
self.contentOffset = (CGPoint) {0, 0};
self.contentInset = UIEdgeInsetsMake(0, 0, 0, 0);
}
}
- (BOOL)refreshable {
return self.scrollEnabled;
}
- (void)setContentSize:(CGSize)contentSize {
[super setContentSize:contentSize];
}
@end

View File

@@ -0,0 +1,25 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/28.
//
#import <Foundation/Foundation.h>
#import "DoricStackNode.h"
@interface DoricFlowLayoutItemNode : DoricStackNode
@end

View File

@@ -0,0 +1,48 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/28.
//
#import "DoricFlowLayoutItemNode.h"
@interface DoricFlowLayoutItemView : DoricStackView
@end
@implementation DoricFlowLayoutItemView
@end
@interface DoricFlowLayoutItemNode ()
@end
@implementation DoricFlowLayoutItemNode
- (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [super initWithContext:doricContext]) {
self.reusable = YES;
}
return self;
}
- (void)initWithSuperNode:(DoricSuperNode *)superNode {
[super initWithSuperNode:superNode];
self.reusable = YES;
}
- (DoricStackView *)build {
return [DoricFlowLayoutItemView new];
}
@end

View File

@@ -0,0 +1,24 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/28.
//
#import <Foundation/Foundation.h>
#import "DoricSuperNode.h"
@interface DoricFlowLayoutNode : DoricSuperNode<UICollectionView *>
@end

View File

@@ -0,0 +1,372 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// Created by pengfei.zhou on 2019/11/28.
//
#import "DoricFlowLayoutNode.h"
#import "DoricFlowLayoutItemNode.h"
#import "DoricExtensions.h"
#import <JavaScriptCore/JavaScriptCore.h>
@protocol DoricFlowLayoutDelegate
- (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath;
- (CGFloat)doricFlowLayoutColumnSpace;
- (CGFloat)doricFlowLayoutRowSpace;
- (NSInteger)doricFlowLayoutColumnCount;
@end
@interface DoricFlowLayout : UICollectionViewLayout
@property(nonatomic, readonly) NSInteger columnCount;
@property(nonatomic, readonly) CGFloat columnSpace;
@property(nonatomic, readonly) CGFloat rowSpace;
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSNumber *> *columnHeightInfo;
@property(nonatomic, weak) id <DoricFlowLayoutDelegate> delegate;
@end
@implementation DoricFlowLayout
- (instancetype)init {
if (self = [super init]) {
_columnHeightInfo = [NSMutableDictionary new];
}
return self;
}
- (NSInteger)columnCount {
return self.delegate.doricFlowLayoutColumnCount ?: 2;
}
- (CGFloat)columnSpace {
return self.delegate.doricFlowLayoutColumnSpace ?: 0;
}
- (CGFloat)rowSpace {
return self.delegate.doricFlowLayoutRowSpace ?: 0;
}
- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds {
return YES;
}
- (void)prepareLayout {
[super prepareLayout];
for (int i = 0; i < self.columnCount; i++) {
self.columnHeightInfo[@(i)] = @(0);
}
}
- (NSArray *)layoutAttributesForElementsInRect:(CGRect)rect {
for (int i = 0; i < self.columnCount; i++) {
self.columnHeightInfo[@(i)] = @(0);
}
NSMutableArray *array = [NSMutableArray array];
NSInteger count = [self.collectionView numberOfItemsInSection:0];
for (int i = 0; i < count; i++) {
UICollectionViewLayoutAttributes *attrs = [self layoutAttributesForItemAtIndexPath:[NSIndexPath indexPathForItem:i inSection:0]];
[array addObject:attrs];
}
return array;
}
- (UICollectionViewLayoutAttributes *)layoutAttributesForItemAtIndexPath:(NSIndexPath *)indexPath {
NSNumber *minYOfColumn = @(0);
for (NSNumber *key in self.columnHeightInfo.allKeys) {
if ([self.columnHeightInfo[key] floatValue] < [self.columnHeightInfo[minYOfColumn] floatValue]) {
minYOfColumn = key;
}
}
CGFloat width = [self.delegate doricFlowLayoutItemWidthAtIndexPath:indexPath];
CGFloat height = [self.delegate doricFlowLayoutItemHeightAtIndexPath:indexPath];
CGFloat x = (width + self.columnSpace) * [minYOfColumn integerValue];
CGFloat y = [self.columnHeightInfo[minYOfColumn] floatValue];
if (y > 0) {
y += self.rowSpace;
}
if (width == self.collectionView.width) {
CGFloat maxY = 0;
for (NSNumber *column in self.columnHeightInfo.allValues) {
maxY = MAX(maxY, [column floatValue]);
}
y = maxY + self.rowSpace;
} else {
self.columnHeightInfo[minYOfColumn] = @(y + height);
}
UICollectionViewLayoutAttributes *attrs = [UICollectionViewLayoutAttributes layoutAttributesForCellWithIndexPath:indexPath];
attrs.frame = CGRectMake(x, y, width, height);
return attrs;
}
- (CGSize)collectionViewContentSize {
CGFloat width = self.collectionView.width;
CGFloat height = 0;
for (NSNumber *column in self.columnHeightInfo.allValues) {
height = MAX(height, [column floatValue]);
}
return CGSizeMake(width, height);
}
@end
@interface DoricFlowLayoutViewCell : UICollectionViewCell
@property(nonatomic, strong) DoricFlowLayoutItemNode *viewNode;
@end
@implementation DoricFlowLayoutViewCell
@end
@interface DoricFlowLayoutView : UICollectionView
@end
@implementation DoricFlowLayoutView
- (CGSize)sizeThatFits:(CGSize)size {
if (self.subviews.count > 0) {
CGFloat width = size.width;
CGFloat height = size.height;
for (UIView *child in self.subviews) {
CGSize childSize = [child measureSize:size];
width = MAX(childSize.width, width);
height = MAX(childSize.height, height);
}
return CGSizeMake(width, height);
}
return size;
}
- (void)layoutSelf:(CGSize)targetSize {
[super layoutSelf:targetSize];
[self reloadData];
}
@end
@interface DoricFlowLayoutNode () <UICollectionViewDataSource, UICollectionViewDelegate, DoricFlowLayoutDelegate>
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSString *> *itemViewIds;
@property(nonatomic, strong) NSMutableDictionary <NSNumber *, NSValue *> *itemSizeInfo;
@property(nonatomic, assign) NSUInteger itemCount;
@property(nonatomic, assign) NSUInteger batchCount;
@property(nonatomic, assign) NSUInteger columnCount;
@property(nonatomic, assign) CGFloat columnSpace;
@property(nonatomic, assign) CGFloat rowSpace;
@property(nonatomic, copy) NSString *renderItemFuncId;
@property(nonatomic, copy) NSString *onLoadMoreFuncId;
@property(nonatomic, copy) NSString *loadMoreViewId;
@property(nonatomic, assign) BOOL loadMore;
@end
@implementation DoricFlowLayoutNode
- (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [super initWithContext:doricContext]) {
_itemViewIds = [NSMutableDictionary new];
_itemSizeInfo = [NSMutableDictionary new];
_batchCount = 15;
_columnCount = 2;
}
return self;
}
- (UICollectionView *)build {
DoricFlowLayout *flowLayout = [[DoricFlowLayout alloc] init];
flowLayout.delegate = self;
return [[[DoricFlowLayoutView alloc] initWithFrame:CGRectZero
collectionViewLayout:flowLayout]
also:^(UICollectionView *it) {
it.backgroundColor = [UIColor whiteColor];
it.pagingEnabled = YES;
it.delegate = self;
it.dataSource = self;
[it registerClass:[DoricFlowLayoutViewCell class] forCellWithReuseIdentifier:@"doricCell"];
[it registerClass:[DoricFlowLayoutViewCell class] forCellWithReuseIdentifier:@"doricLoadMoreCell"];
}];
}
- (void)blendView:(UICollectionView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"columnSpace" isEqualToString:name]) {
self.columnSpace = [prop floatValue];
[self.view.collectionViewLayout invalidateLayout];
} else if ([@"rowSpace" isEqualToString:name]) {
self.rowSpace = [prop floatValue];
[self.view.collectionViewLayout invalidateLayout];
} else if ([@"columnCount" isEqualToString:name]) {
self.columnCount = [prop unsignedIntegerValue];
[self.view reloadData];
[self.view.collectionViewLayout invalidateLayout];
} else if ([@"itemCount" isEqualToString:name]) {
self.itemCount = [prop unsignedIntegerValue];
[self.view reloadData];
} else if ([@"renderItem" isEqualToString:name]) {
if ([self.renderItemFuncId isEqualToString:prop]) {
} else {
[self.itemViewIds removeAllObjects];
[self clearSubModel];
[self.view reloadData];
self.renderItemFuncId = prop;
}
} else if ([@"batchCount" isEqualToString:name]) {
self.batchCount = [prop unsignedIntegerValue];
} else if ([@"onLoadMore" isEqualToString:name]) {
self.onLoadMoreFuncId = prop;
} else if ([@"loadMoreView" isEqualToString:name]) {
self.loadMoreViewId = prop;
} else if ([@"loadMore" isEqualToString:name]) {
self.loadMore = [prop boolValue];
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (NSDictionary *)itemModelAt:(NSUInteger)position {
if (position >= self.itemCount) {
return [self subModelOf:self.loadMoreViewId];
}
NSString *viewId = self.itemViewIds[@(position)];
if (viewId && viewId.length > 0) {
return [self subModelOf:viewId];
} else {
DoricAsyncResult *result = [self callJSResponse:@"renderBunchedItems", @(position), @(self.batchCount), nil];
JSValue *models = [result waitUntilResult];
NSArray *array = [models toArray];
[array enumerateObjectsUsingBlock:^(NSDictionary *obj, NSUInteger idx, BOOL *stop) {
NSString *thisViewId = obj[@"id"];
[self setSubModel:obj in:thisViewId];
NSUInteger pos = position + idx;
self.itemViewIds[@(pos)] = thisViewId;
}];
return array[0];
}
}
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
__block DoricViewNode *ret = nil;
[self.doricContext.driver ensureSyncInMainQueue:^{
for (UICollectionViewCell *collectionViewCell in self.view.visibleCells) {
if ([collectionViewCell isKindOfClass:[DoricFlowLayoutViewCell class]]) {
DoricFlowLayoutItemNode *node = ((DoricFlowLayoutViewCell *) collectionViewCell).viewNode;
if ([viewId isEqualToString:node.viewId]) {
ret = node;
break;
}
}
}
}];
return ret;
}
- (void)blendSubNode:(NSDictionary *)subModel {
dispatch_async(dispatch_get_main_queue(), ^{
NSString *viewId = subModel[@"id"];
DoricViewNode *viewNode = [self subNodeWithViewId:viewId];
if (viewNode) {
[viewNode blend:subModel[@"props"]];
} else {
NSMutableDictionary *model = [[self subModelOf:viewId] mutableCopy];
[self recursiveMixin:subModel to:model];
[self setSubModel:model in:viewId];
}
[self.itemViewIds enumerateKeysAndObjectsUsingBlock:^(NSNumber *_Nonnull key, NSString *_Nonnull obj, BOOL *_Nonnull stop) {
if ([viewId isEqualToString:obj]) {
*stop = YES;
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[key integerValue] inSection:0];
[UIView performWithoutAnimation:^{
[self.view reloadItemsAtIndexPaths:@[indexPath]];
}];
}
}];
});
}
- (void)callItem:(NSUInteger)position size:(CGSize)size {
NSValue *old = self.itemSizeInfo[@(position)];
if (old && CGSizeEqualToSize([old CGSizeValue], size)) {
return;
}
self.itemSizeInfo[@(position)] = [NSValue valueWithCGSize:size];
[self.view.collectionViewLayout invalidateLayout];
}
- (NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
return self.itemCount + (self.loadMore ? 1 : 0);
}
- (__kindof UICollectionViewCell *)collectionView:(UICollectionView *)collectionView cellForItemAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
NSDictionary *model = [self itemModelAt:position];
NSDictionary *props = model[@"props"];
DoricFlowLayoutViewCell *cell = [collectionView dequeueReusableCellWithReuseIdentifier:@"doricCell" forIndexPath:indexPath];
if (!cell.viewNode) {
DoricFlowLayoutItemNode *itemNode = [[DoricFlowLayoutItemNode alloc] initWithContext:self.doricContext];
[itemNode initWithSuperNode:self];
cell.viewNode = itemNode;
[cell.contentView addSubview:itemNode.view];
}
DoricFlowLayoutItemNode *node = cell.viewNode;
node.viewId = model[@"id"];
[node blend:props];
CGFloat width = (collectionView.width - (self.columnCount - 1) * self.columnSpace) / self.columnCount;
CGSize size = [node.view measureSize:CGSizeMake(width, collectionView.height)];
if (position > 0 && position >= self.itemCount && self.onLoadMoreFuncId) {
size = CGSizeMake(collectionView.width, size.height);
[self callJSResponse:self.onLoadMoreFuncId, nil];
}
[node.view layoutSelf:size];
[self callItem:position size:size];
return cell;
}
- (CGFloat)doricFlowLayoutItemHeightAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
NSValue *value = self.itemSizeInfo[@(position)];
if (value) {
return [value CGSizeValue].height;
} else {
return 100;
}
}
- (CGFloat)doricFlowLayoutItemWidthAtIndexPath:(NSIndexPath *)indexPath {
NSUInteger position = (NSUInteger) indexPath.row;
NSValue *value = self.itemSizeInfo[@(position)];
if (value) {
return [value CGSizeValue].width;
} else {
return 100;
}
}
- (CGFloat)doricFlowLayoutColumnSpace {
return self.columnSpace;
}
- (CGFloat)doricFlowLayoutRowSpace {
return self.rowSpace;
}
- (NSInteger)doricFlowLayoutColumnCount {
return self.columnCount;
}
@end

View File

@@ -0,0 +1,30 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricGroupNode.h
// Doric
//
// Created by pengfei.zhou on 2019/7/30.
//
#import "DoricSuperNode.h"
NS_ASSUME_NONNULL_BEGIN
@interface DoricGroupNode <V:UIView *> : DoricSuperNode<V>
@end
NS_ASSUME_NONNULL_END

View File

@@ -0,0 +1,170 @@
/*
* Copyright [2019] [Doric.Pub]
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// DoricGroupNode.m
// Doric
//
// Created by pengfei.zhou on 2019/7/30.
//
#import "DoricGroupNode.h"
@interface DoricGroupNode ()
@property(nonatomic, copy) NSArray<DoricViewNode *> *childNodes;
@property(nonatomic, copy) NSArray <NSString *> *childViewIds;
@end
@implementation DoricGroupNode
- (instancetype)initWithContext:(DoricContext *)doricContext {
if (self = [super initWithContext:doricContext]) {
_childNodes = @[];
_childViewIds = @[];
}
return self;
}
- (UIView *)build {
UIView *ret = [[UIView alloc] init];
ret.clipsToBounds = YES;
return ret;
}
- (void)blendView:(UIView *)view forPropName:(NSString *)name propValue:(id)prop {
if ([@"children" isEqualToString:name]) {
self.childViewIds = prop;
} else {
[super blendView:view forPropName:name propValue:prop];
}
}
- (void)blend:(NSDictionary *)props {
[super blend:props];
[self configChildNodes];
}
- (DoricLayoutConfig *)generateDefaultLayoutParams {
DoricLayoutConfig *params = [[DoricLayoutConfig alloc] init];
return params;
}
- (void)configChildNodes {
NSMutableArray *childNodes = [self.childNodes mutableCopy];
for (NSUInteger idx = 0; idx < self.childViewIds.count; idx++) {
NSString *viewId = self.childViewIds[idx];
NSDictionary *model = [self subModelOf:viewId];
NSString *type = model[@"type"];
if (idx < self.childNodes.count) {
DoricViewNode *oldNode = childNodes[idx];
if ([viewId isEqualToString:oldNode.viewId]) {
///Same,skip
} else {
if (self.reusable) {
if ([oldNode.type isEqualToString:type]) {
///Same type,can be reused
oldNode.viewId = viewId;
[oldNode blend:model[@"props"]];
} else {
///Replace this view
[childNodes removeObjectAtIndex:idx];
[oldNode.view removeFromSuperview];
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
if ([viewNode isKindOfClass:[DoricGroupNode class]]) {
((DoricGroupNode *) viewNode).reusable = self.reusable;
}
viewNode.viewId = viewId;
[viewNode initWithSuperNode:self];
[viewNode blend:model[@"props"]];
[childNodes insertObject:viewNode atIndex:idx];
[self.view insertSubview:viewNode.view atIndex:idx];
}
} else {
///Find in remain nodes
NSInteger position = -1;
for (NSUInteger start = idx + 1; start < childNodes.count; start++) {
DoricViewNode *node = childNodes[start];
if ([viewId isEqualToString:node.viewId]) {
position = start;
break;
}
}
if (position >= 0) {
///Found ,swap idx,position
DoricViewNode *reused = childNodes[(NSUInteger) position];
[childNodes removeObjectAtIndex:(NSUInteger) position];
[childNodes removeObjectAtIndex:idx];
[childNodes insertObject:reused atIndex:idx];
[childNodes insertObject:oldNode atIndex:(NSUInteger) position];
///View swap index
[reused.view removeFromSuperview];
[oldNode.view removeFromSuperview];
[self.view insertSubview:reused.view atIndex:idx];
[self.view insertSubview:oldNode.view atIndex:position];
} else {
///Not found,insert
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
viewNode.viewId = viewId;
[viewNode initWithSuperNode:self];
[viewNode blend:model[@"props"]];
[childNodes insertObject:viewNode atIndex:idx];
[self.view insertSubview:viewNode.view atIndex:idx];
}
}
}
} else {
/// Insert
DoricViewNode *viewNode = [DoricViewNode create:self.doricContext withType:type];
if ([viewNode isKindOfClass:[DoricGroupNode class]]) {
((DoricGroupNode *) viewNode).reusable = self.reusable;
}
viewNode.viewId = viewId;
[viewNode initWithSuperNode:self];
[viewNode blend:model[@"props"]];
[childNodes addObject:viewNode];
[self.view addSubview:viewNode.view];
}
}
NSUInteger count = childNodes.count;
for (NSUInteger idx = self.childViewIds.count; idx < count; idx++) {
DoricViewNode *viewNode = childNodes.lastObject;
[childNodes removeLastObject];
[viewNode.view removeFromSuperview];
}
self.childNodes = [childNodes copy];
}
- (void)blendSubNode:(NSDictionary *)subModel {
NSString *viewId = subModel[@"id"];
[self.childNodes enumerateObjectsUsingBlock:^(DoricViewNode *obj, NSUInteger idx, BOOL *stop) {
if ([viewId isEqualToString:obj.viewId]) {
[obj blend:subModel[@"props"]];
*stop = YES;
}
}];
}
- (DoricViewNode *)subNodeWithViewId:(NSString *)viewId {
for (DoricViewNode *viewNode in self.childNodes) {
if ([viewId isEqualToString:viewNode.viewId]) {
return viewNode;
}
}
return nil;
}
@end

Some files were not shown because too many files have changed in this diff Show More