ScriptMediator: registerFunction()
ネイティブ側で定義した関数を指定した関数名で登録し、JavaScript側から呼び出せるようにします。
構文
suspend ScriptMediator.registerFunction(isSync, functionName, funciton): Any?
ScriptMediator.registerFunction(isSync, functionName, function, completionHandler): Unit
ScriptMediator.registerFunction(isSync, functionName, function) async -> Any?
ScriptMediator.registerFunction(isSync, functionName, function, completionHandler) -> Void
引数
-
isSync:BooleanJavaScript側で同期関数として登録するかどうかです。
引数
isSyncの値がtrueなら、引数functionとして与えた関数をJavaScript側から呼び出した際、JavaScript上では関数呼び出しは同期関数として行われます。つまりJavaScript側では、登録されたネイティブ関数の実行が完了し値を返すまで、次の処理へ進みません。引数
isSyncの値がfalseならJavaScript上では関数呼び出しは非同期関数として行われます。つまりJavaScript側では、登録されたネイティブ関数の実行が完了する際に履行されるPromiseが即時に返されます。 -
functionName:String登録する関数の名前です。
この名前はJavaScript側で登録されたネイティブ関数を呼び出す際に使います。 JavaScript側では、引数
functionNameとして指定した名前がそのまま関数名として使われます。JavaScriptの識別子- JavaScriptにおいて、識別子として使える文字種別と文字の出現位置には制限があります。
使用の制限された文字を含むプロパティへアクセスするには、
object["プロパティ名"]のように、プロパティ名を文字列として指定する必要があります。 詳細は MDN, JavaScriptリファレンス, 字句文法を参照してください。
- JavaScriptにおいて、識別子として使える文字種別と文字の出現位置には制限があります。
使用の制限された文字を含むプロパティへアクセスするには、
-
function:(Array<out Any?>) -> Any?登録する関数です。
引数として任意の型の配列を1つ受けとり、任意の型の値を返すラムダ式を指定します。
登録された関数は、JavaScript側から
Alier.Native.<関数名>に対して関数呼び出しを行うことで、実行できるようになります(<関数名>には引数functionNameで指定した名前を使います)。 -
completionHandler:((Any?) -> Unit)?(省略可)関数登録の完了後に呼び出されるコールバック関数です。
nullを指定した場合、何も行いません。この引数の指定は任意です。指定がない場合、この関数は
suspend関数として実行されます。suspend 関数の実行suspend関数の呼び出しはsuspend関数の定義部にのみ書けます。 通常の(suspendでない)関数からsuspend関数を実行するには、コルーチンビルダー(suspend関数を受け取りJobを生成する関数)を使います。 詳細は Kotlin Documentation, Coroutines basics を参照してください。
-
isSync:Bool?JavaScript側で同期関数として登録するかどうかです。
引数
isSyncの値がtrueなら、引数functionとして与えた関数をJavaScript側から呼び出した際、JavaScript上では関数呼び出しは同期関数として行われます。つまりJavaScript側では、登録されたネイティブ関数の実行が完了し値を返すまで、次の処理へ進みません。引数
isSyncの値がfalseならJavaScript上では関数呼び出しは非同期関数として行われます。つまりJavaScript側では、登録されたネイティブ関数の実行が完了する際に履行されるPromiseが即時に返されます。 -
functionName:String登録する関数の名前です。
この名前はJavaScript側で登録されたネイティブ関数を呼び出す際に使います。 JavaScript側では、引数
functionNameとして指定した名前がそのまま関数名として使われます。JavaScriptの識別子- JavaScriptにおいて、識別子として使える文字種別と文字の出現位置には制限があります。
使用の制限された文字を含むプロパティへアクセスするには、
object["プロパティ名"]のように、プロパティ名を文字列として指定する必要があります。 詳細は MDN, JavaScriptリファレンス, 字句文法を参照してください。
- JavaScriptにおいて、識別子として使える文字種別と文字の出現位置には制限があります。
使用の制限された文字を含むプロパティへアクセスするには、
-
function:([Any?]) -> Any?|([Any?]) throws -> Any?登録する関数です。
引数として任意の型の配列を1つ受けとり、任意の型の値を返すクロージャを指定します。
登録された関数は、JavaScript側から
Alier.Native.<関数名>に対して関数呼び出しを行うことで、実行できるようになります(<関数名>には引数functionNameで指定した名前を使います)。 -
completionHandler:((Any?) -> Void)?(省略可)関数登録の完了後に呼び出されるコールバック関数です。
nilを指定した場合、何も行いません。この引数の指定は任意です。指定がない場合、この関数は
async関数として実行されます。async関数は iOS 15 以上でのみサポートされています。async 関数の実行async関数の呼び出しは、async関数の定義部かアプリケーションのエントリポイントとなる(つまりトップレベルの)関数の定義部にのみ書けます(エントリポイントは@main属性の与えられたデータ型が持つstatic main()関数として定義します)。 通常の(asyncでない)関数からasync関数を実行するには、Taskを使います。 詳細は The Swift Programming Language, Concurrency, The Swift Programming Language, Attributes を参照してください。
-
JavaScriptの型システムにおける固定長の数値型は
number型のみです。number型の値はIEEE754 binary64 形式の 64 ビット2進浮動小数点数として表されます。 これは Kotlin や Swift におけるDouble型と同じです。従ってAlierフレームワークでは、JavaScript側から与えられた
number型の値は、ネイティブ側ではDoubleとして扱われます。 整数を期待するネイティブ関数においても、直接Intのような整数型へキャストを行うのではなく、Doubleとしてキャストした上で適切な変換関数を呼び出す必要があります。
返値: Any?
関数登録の結果です。
返値は suspend 関数として呼び出した場合にのみに返ります。
引数 completionHandler を指定した場合、この関数は返値を持ちません。
関数登録の結果です。
返値は async 関数として呼び出した場合にのみに返ります。
引数 completionHandler を指定した場合、この関数は返値を持ちません。
例外
IllegalArgumentException- 引数
functionNameで指定した名前が既に登録されている場合。
- 引数
InvocationError.FUNCTION_NAME_DUPLICATED- 引数
functionNameで指定した名前が既に登録されている場合。
- 引数
例
以下では registerFunction() メソッドを使って、Kotlin側で定義した関数(ラムダ式)をJavaScript側から呼び出せるようにする例を示します。
val add: (Array<out Any?>) -> Any? = { args ->
if (args.size < 2) { return 0 }
val x: Number = args[0] as? Number ?: return 0
val y: Number = args[1] as? Number ?: return x.toInt()
x.toInt() + y.toInt()
}
val collatz: ((Array<out Any?>) -> Any?) = { args ->
val seq = arrayListOf<Int>()
if (args.size >= 1) {
val n0 = (args[0] as? Number)?.toInt()
if (n0 != null && n0 != 0) {
var n = if (n0 < 0) { -n0 } else { n0 }
while (n >= 1) {
n = n / (n.and(-n))
if (n == 1) { break }
seq.add(n)
n = 3 * n + 1
}
}
}
seq.toTypedArray()
}
try {
// Alier.Native.add() をJavaScript側に定義します。
// registerFunction は既に "add" に対して関数が登録されている場合に
// IllegalArgumentException 例外を送ります。
scriptMediator.registerFunction(
isSync = false,
functionName = "add",
function = add
)
// isSync を true にすると、JavaScript 側では Promise を返す関数
// として定義されます。
// Promise の履行を待ち合わせることで関数の実行結果が得られます。
scriptMediator.registerFunction(
isSync = true,
functionName = "collatz",
function = collatz
)
} catch (error: IllegalArgumentException) {
// ここに例外からの復旧処理を書きます。
// 復旧処理の後、後続処理を継続できるならブロックを抜け、
// そうでないなら例外を再度 throw します。
}
以下では registerFunction() メソッドを使って、Swift側で定義した関数(クロージャ)をJavaScript側から呼び出せるようにする例を示します。
// 登録する関数を定義します。
let add: ([Any?]) -> Any? = { args in
if args.count < 2 { return 0 }
guard let x = args[0] as? Double else { return 0 }
guard let y = args[1] as? Double else { return Int(x) }
return Int(x) + Int(y)
}
let collatz: ([Any?]) -> Any? = { args in
var seq: [Int] = []
if args.count < 1 { return seq }
guard let n0 = args[0] as? Double else { return seq }
var n = Int(n0)
if n == 0 { return seq }
if n < 0 { n = -n }
while n >= 1 {
n /= (n & (-n))
if n == 1 { break }
seq.append(n)
n = 3 * n + 1
}
return seq
}
do {
// Alier.Native.add() をJavaScript側に定義します。
// registerFunction は既に "add" に対して関数が登録されている場合に
// 例外を送ります。
try scriptMediator.registerFunction(
isSync : false,
functionName: "add",
function : add
)
// isSync を true にすると、JavaScript 側では Promise を返す関数
// として定義されます。
// Promise の履行を待ち合わせることで関数の実行結果が得られます。
try scriptMediator.registerFunction(
isSync : true,
functionName: "collatz",
function : collatz
)
} catch {
// ここに例外からの復旧処理を書きます。
// 復旧処理の後、後続処理を継続できるならブロックを抜け、
// そうでないなら例外を再度 throw します。
}
JavaScript 側でネイティブアプリ側から登録した関数を呼び出します。
// add() は同期関数として登録されているため、計算結果がそのまま返されます。
// 定義側では単一の配列を受け取りますが、
// 呼び出し側では単に必要な個数の引数を指定します。
console.log(Alier.Native.add(1, 2));
// collatz() は非同期関数として登録されているため、Promise が返されます。
// 計算結果を得るには await 演算子を使います。
console.log(await Alier.Native.collatz(42));
解説
ネイティブ側で定義した関数を指定した関数名で登録し、JavaScript側から呼び出せるようにします。
登録された関数はJavaScript側で Alier.Native.<関数名>() を呼び出すことで実行されます。<関数名> の部分は引数 functionName で与えた名前が使われます。
また、登録側の関数は単一の配列を引数を受け取りますが、呼び出し側では単に必要な個数の引数を指定します(配列への変換はフレームワーク側で行われます)。
例えば引数 functionName として "add" を指定したなら、JavaScript側には Alier.Native に対して add という名前のプロパティが追加されます。
また登録された関数 add が引数配列の最初の 2 つを使うなら、呼び出し側では Alier.Native.add(1, 2) のように 2 つの引数を指定します。
登録しようとした名前が既に使われている場合、IllegalArgumentException が発生します。
重複の検査が不要で、常に関数の登録を成功させたい場合、代わりに replaceFunction() を使用してください。
ネイティブ側で定義した関数を指定した関数名で登録し、JavaScript側から呼び出せるようにします。
登録された関数はJavaScript側で Alier.Native.<関数名>() を呼び出すことで実行されます。<関数名> の部分は引数 functionName で与えた名前が使われます。
また、登録側の関数は単一の配列を引数を受け取りますが、呼び出し側では単に必要な個数の引数を指定します(配列への変換はフレームワーク側で行われます)。
例えば引数 functionName として "add" を指定したなら、JavaScript側には Alier.Native に対して add という名前のプロパティが追加されます。
また登録された関数 add が引数配列の最初の 2 つを使うなら、呼び出し側では Alier.Native.add(1, 2) のように 2 つの引数を指定します。
登録しようとした名前が既に使われている場合、InvocationError.FUNCTION_NAME_DUPLICATED が発生します。
重複の検査が不要で、常に関数の登録を成功させたい場合、代わりに replaceFunction() を使用してください。