---
title: Swift + JavaScriptCore
pagination_prev: demos/bigdata/index
pagination_next: solutions/input
---
import current from '/version.js';
import CodeBlock from '@theme/CodeBlock';
iOS and MacOS ship with the JavaScriptCore framework for running JS code from
Swift and Objective-C. Hybrid function invocation is tricky, but explicit data
passing is straightforward. The demo shows a standalone Swift sample for MacOS.
The [SheetJS Standalone scripts](/docs/getting-started/installation/standalone)
can be parsed and evaluated in a JSC context.
:::danger Platform Limitations
JavaScriptCore is primarily deployed in MacOS and iOS applications. There is
some experimental support through the Bun runtime, but apps intending to support
Windows / Linux / Android should try to embed [V8](/docs/demos/engines/v8).
:::
## Integration Details
Binary strings can be passed back and forth using `String.Encoding.isoLatin1`.
_Initialize JavaScriptCore_
JSC does not provide a `global` variable. It can be created in one line:
```swift
var context: JSContext!
do {
context = JSContext();
context.exceptionHandler = { _, X in if let e = X { print(e.toString()!); }; };
// highlight-next-line
context.evaluateScript("var global = (function(){ return this; }).call(null);");
} catch { print(error.localizedDescription); }
```
_Load SheetJS Scripts_
The main library can be loaded by reading the scripts from the file system and
evaluating in the JSC context:
```swift
let src = try String(contentsOfFile: "xlsx.full.min.js");
context.evaluateScript(src);
```
To confirm the library is loaded, `XLSX.version` can be inspected:
```swift
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
if let ver = XLSX.objectForKeyedSubscript("version") { print(ver.toString()); }
```
### Reading Files
`String(contentsOf:encoding:)` reads from a path and returns an encoded string:
```swift
/* read sheetjs.xls as Base64 string */
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
```
This string can be loaded into the JS engine and processed:
```swift
/* load data in JSC */
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol));
/* `payload` (the "forKeyedSubscript" parameter) is a binary string */
context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});");
```
Direct Read (click to show)
`Uint8Array` data can be passed directly, skipping string encoding and decoding:
```swift
let url = URL(fileURLWithPath: file)
var data: Data! = try Data(contentsOf: url);
let count = data.count;
/* Note: the operations must be performed in the closure! */
let wb: JSValue! = data.withUnsafeMutableBytes { (dataPtr: UnsafeMutableRawBufferPointer) in
// highlight-next-line
let ab: JSValue! = JSValue(jsValueRef: JSObjectMakeTypedArrayWithBytesNoCopy(context.jsGlobalContextRef, kJSTypedArrayTypeUint8Array, dataPtr.baseAddress, count, nil, nil, nil), in: context)
/* prepare options argument */
context.evaluateScript(String(format: "var readopts = {type:'array', dense:true}"));
let readopts: JSValue = context.objectForKeyedSubscript("readopts");
/* call XLSX.read */
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
let readfunc: JSValue = XLSX.objectForKeyedSubscript("read");
return readfunc.call(withArguments: [ab, readopts]);
}
```
For broad compatibility with Swift versions, the demo uses the String method.