diff --git a/SConstruct b/SConstruct index c943b12..6e20e3c 100644 --- a/SConstruct +++ b/SConstruct @@ -24,7 +24,7 @@ opts.Add(EnumVariable('arch', "Compilation Architecture", '', ['', 'arm64', 'arm opts.Add(BoolVariable('simulator', "Compilation platform", 'no')) opts.Add(BoolVariable('use_llvm', "Use the LLVM / Clang compiler", 'no')) opts.Add(PathVariable('target_path', 'The path where the lib is installed.', 'bin/')) -opts.Add(EnumVariable('plugin', 'Plugin to build', '', ['', 'apn', 'arkit', 'camera', 'icloud', 'gamecenter', 'inappstore', 'photo_picker'])) +opts.Add(EnumVariable('plugin', 'Plugin to build', '', ['', 'apn', 'arkit', 'camera', 'icloud', 'gamecenter', 'inappstore', 'photo_picker', 'healthkit'])) opts.Add(EnumVariable('version', 'Godot version to target', '', ['', '3.x', '4.0'])) # Updates the environment with the option variables. diff --git a/plugins/healthkit/README.md b/plugins/healthkit/README.md new file mode 100644 index 0000000..640a219 --- /dev/null +++ b/plugins/healthkit/README.md @@ -0,0 +1,44 @@ +# Godot iOS HealthKit plugin + +## Enum + +Type: `AuthorizationStatus` +Values: `AUTHORIZATION_STATUS_NOT_DETERMINED`, `AUTHORIZATION_STATUS_DENIED`, `AUTHORIZATION_STATUS_AUTHORIZED` + +Type: `ObjectType` +Values: `OBJECT_TYPE_UNKNOWN`, `OBJECT_TYPE_QUANTITY_TYPE_STEP_COUNT`, `OBJECT_TYPE_QUANTITY_TYPE_ACTIVE_ENERY_BURNED` + +Type: `QuantityType` +Values: `QUANTITY_TYPE_UNKNOWN`, `QUANTITY_TYPE_STEP_COUNT`, `QUANTITY_TYPE_ACTIVE_ENERY_BURNED` + +## Methods + +`bool is_health_data_available()` + +- Check if HealthKit is available on device. + +`Error request_authorization(Vector to_share, Vector to_read)` + +- Requests authorization to share and read the given object types. + +`SharingAuthorizationStatus authorization_status_for_type(ObjectType object_type)` + +- Used to determine if the user is permitted to share the given object type. Should be called before actually sharing. + +`Error execute_statistics_query(QuantityType quantity_type, int start_date, int end_date)` + +- Starts a query to query health data of the given quantity type. + +## Signals + +`authorization_complete(int object_type, int status)` + +- Called when the authorization has completed. + +`statistics_query_completed(int quantity_type, float value)` + +- Called when the statistics query has completed for the given quantity type. + +`statistics_query_failed(int quantity_type, int error_code)` + +- Called when the statistics query has failed for the given quantity type. diff --git a/plugins/healthkit/healthkit.gdip b/plugins/healthkit/healthkit.gdip new file mode 100644 index 0000000..db878f7 --- /dev/null +++ b/plugins/healthkit/healthkit.gdip @@ -0,0 +1,17 @@ +[config] +name="HealthKit" +binary="healthkit.xcframework" + +initialization="register_healthkit_types" +deinitialization="unregister_healthkit_types" + +[dependencies] +linked=[] +embedded=[] +system=[] + +capabilities=[] + +files=[] + +[plist] diff --git a/plugins/healthkit/healthkit.h b/plugins/healthkit/healthkit.h new file mode 100644 index 0000000..71b9938 --- /dev/null +++ b/plugins/healthkit/healthkit.h @@ -0,0 +1,93 @@ +/*************************************************************************/ +/* healthkit.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef HEALTHKIT_H +#define HEALTHKIT_H + +#include "core/version.h" + +#if VERSION_MAJOR == 4 +#include "core/object/class_db.h" +#include "core/templates/vector.h" +#else +#include "core/object.h" +#include "core/vector.h" +#endif + +class HealthKit : public Object { + GDCLASS(HealthKit, Object); + + static HealthKit *_instance; + + static void _bind_methods(); + +public: + + enum AuthorizationStatus { + AUTHORIZATION_STATUS_NOT_DETERMINED, + AUTHORIZATION_STATUS_DENIED, + AUTHORIZATION_STATUS_AUTHORIZED, + }; + + enum SharingAuthorizationStatus { + SHARING_AUTHORIZATION_STATUS_NOT_DETERMINED, + SHARING_AUTHORIZATION_STATUS_DENIED, + SHARING_AUTHORIZATION_STATUS_AUTHORIZED, + }; + + enum ObjectType { + OBJECT_TYPE_UNKNOWN, + OBJECT_TYPE_QUANTITY_TYPE_STEP_COUNT, + OBJECT_TYPE_QUANTITY_TYPE_ACTIVE_ENERGY_BURNED, + }; + + enum QuantityType { + QUANTITY_TYPE_UNKNOWN, + QUANTITY_TYPE_STEP_COUNT, + QUANTITY_TYPE_ACTIVE_ENERGY_BURNED, + }; + + static HealthKit *get_singleton(); + + bool is_health_data_available() const; + Error request_authorization(Vector to_share, Vector to_read); + SharingAuthorizationStatus authorization_status_for_type(ObjectType object_type); + Error execute_statistics_query(QuantityType quantity_type, int start_date, int end_date); + + HealthKit(); + ~HealthKit(); +}; + +VARIANT_ENUM_CAST(HealthKit::AuthorizationStatus); +VARIANT_ENUM_CAST(HealthKit::SharingAuthorizationStatus); +VARIANT_ENUM_CAST(HealthKit::ObjectType); +VARIANT_ENUM_CAST(HealthKit::QuantityType); + +#endif diff --git a/plugins/healthkit/healthkit.mm b/plugins/healthkit/healthkit.mm new file mode 100644 index 0000000..d974348 --- /dev/null +++ b/plugins/healthkit/healthkit.mm @@ -0,0 +1,235 @@ +/*************************************************************************/ +/* healthkit.mm */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "healthkit.h" + +#if VERSION_MAJOR == 4 +#import "platform/ios/app_delegate.h" +#else +#import "platform/iphone/app_delegate.h" +#endif + +#import +#import +#import + +HealthKit *HealthKit::_instance = NULL; + +static HKHealthStore *_health_store; + +void HealthKit::_bind_methods() { + ClassDB::bind_method(D_METHOD("is_health_data_available"), &HealthKit::is_health_data_available); + ClassDB::bind_method(D_METHOD("request_authorization", "to_share", "to_read"), &HealthKit::request_authorization, DEFVAL(Vector()), DEFVAL(Vector())); + ClassDB::bind_method(D_METHOD("authorization_status_for_type", "object_type"), &HealthKit::authorization_status_for_type); + ClassDB::bind_method(D_METHOD("execute_statistics_query", "quantity_type", "start_date", "end_date"), &HealthKit::execute_statistics_query); + + ADD_SIGNAL(MethodInfo("authorization_completed", PropertyInfo(Variant::INT, "status"))); + ADD_SIGNAL(MethodInfo("statistics_query_completed", PropertyInfo(Variant::INT, "quantity_type"), PropertyInfo(Variant::FLOAT, "value"))); + ADD_SIGNAL(MethodInfo("statistics_query_failed", PropertyInfo(Variant::INT, "quantity_type"), PropertyInfo(Variant::INT, "error_code"))); + + BIND_ENUM_CONSTANT(AUTHORIZATION_STATUS_NOT_DETERMINED); + BIND_ENUM_CONSTANT(AUTHORIZATION_STATUS_DENIED); + BIND_ENUM_CONSTANT(AUTHORIZATION_STATUS_AUTHORIZED); + + BIND_ENUM_CONSTANT(SHARING_AUTHORIZATION_STATUS_NOT_DETERMINED); + BIND_ENUM_CONSTANT(SHARING_AUTHORIZATION_STATUS_DENIED); + BIND_ENUM_CONSTANT(SHARING_AUTHORIZATION_STATUS_AUTHORIZED); + + BIND_ENUM_CONSTANT(OBJECT_TYPE_UNKNOWN); + BIND_ENUM_CONSTANT(OBJECT_TYPE_QUANTITY_TYPE_STEP_COUNT); + BIND_ENUM_CONSTANT(OBJECT_TYPE_QUANTITY_TYPE_ACTIVE_ENERGY_BURNED); + + BIND_ENUM_CONSTANT(QUANTITY_TYPE_UNKNOWN); + BIND_ENUM_CONSTANT(QUANTITY_TYPE_STEP_COUNT); + BIND_ENUM_CONSTANT(QUANTITY_TYPE_ACTIVE_ENERGY_BURNED); +} + +HealthKit *HealthKit::get_singleton() { + return _instance; +} + +bool HealthKit::is_health_data_available() const { + return HKHealthStore.isHealthDataAvailable; +} + +static HKObjectType *_hkobjecttype_from_object_type(HealthKit::ObjectType object_type) { + switch (object_type) { + case HealthKit::OBJECT_TYPE_QUANTITY_TYPE_STEP_COUNT: + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; + case HealthKit::OBJECT_TYPE_QUANTITY_TYPE_ACTIVE_ENERGY_BURNED: + return [HKObjectType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; + case HealthKit::OBJECT_TYPE_UNKNOWN: + default: + NSLog(@"Error unknown object type"); + return nil; + } +} + +static NSSet *_nsset_from_object_type_vector(Vector obj_type_vector) { + NSMutableSet *to_share_nsmutableset = [NSMutableSet set]; + + for (int i = 0; i < obj_type_vector.size(); i++) { + HealthKit::ObjectType object_type = (HealthKit::ObjectType)obj_type_vector[i]; + HKObjectType *object_type_nsobj = _hkobjecttype_from_object_type(object_type); + if (object_type_nsobj == nil) { + NSLog(@"Error while requesting HealthKit authorization."); + return [NSSet set]; + } + [to_share_nsmutableset addObject:object_type_nsobj]; + } + + return [NSSet setWithSet:to_share_nsmutableset]; +} + +Error HealthKit::request_authorization(Vector to_share, Vector to_read) { + NSLog(@"Requesting HealthKit authorization..."); + + if (!is_health_data_available()) { + NSLog(@"HealthKit is not available"); + return ERR_UNAVAILABLE; + } + + NSSet *to_share_nsset = _nsset_from_object_type_vector(to_share); + if (to_share_nsset.count != to_share.size()) { + NSLog(@"Error while requesting HealthKit authorization."); + return ERR_INVALID_PARAMETER; + } + NSSet *to_read_nsset = _nsset_from_object_type_vector(to_read); + if (to_read_nsset.count != to_read.size()) { + NSLog(@"Error while requesting HealthKit authorization."); + return ERR_INVALID_PARAMETER; + } + + [_health_store requestAuthorizationToShareTypes:to_share_nsset readTypes:to_read_nsset completion:^(BOOL success, NSError *error) { + NSLog(@"HealthKit authorization completed."); + + if (error) { + NSLog(@"Error while requesting HealthKit authorization: %@", error); + emit_signal("authorization_completed", AUTHORIZATION_STATUS_NOT_DETERMINED); + return; + } + + if (success) { + NSLog(@"HealthKit authorization succeeded."); + emit_signal("authorization_completed", AUTHORIZATION_STATUS_AUTHORIZED); + } else { + NSLog(@"HealthKit authorization failed."); + emit_signal("authorization_completed", AUTHORIZATION_STATUS_DENIED); + } + }]; + + return OK; +} + +HealthKit::SharingAuthorizationStatus HealthKit::authorization_status_for_type(ObjectType object_type) { + HKObjectType *object_type_nsobj = _hkobjecttype_from_object_type(object_type); + if (object_type_nsobj == nil) { + NSLog(@"Error while requesting HealthKit authorization status."); + return SHARING_AUTHORIZATION_STATUS_NOT_DETERMINED; + } + + HKAuthorizationStatus status = [_health_store authorizationStatusForType:object_type_nsobj]; + + switch (status) { + case HKAuthorizationStatusSharingDenied: + return SHARING_AUTHORIZATION_STATUS_DENIED; + case HKAuthorizationStatusSharingAuthorized: + return SHARING_AUTHORIZATION_STATUS_AUTHORIZED; + case HKAuthorizationStatusNotDetermined: + default: + NSLog(@"Error while requesting HealthKit authorization status."); + return SHARING_AUTHORIZATION_STATUS_NOT_DETERMINED; + } +} + +Error HealthKit::execute_statistics_query(QuantityType quantity_type, int start_date, int end_date) { + NSLog(@"Executing HealthKit statistics query..."); + + if (!is_health_data_available()) { + NSLog(@"HealthKit is not available"); + return ERR_UNAVAILABLE; + } + + NSDate *start_date_nsdate = [NSDate dateWithTimeIntervalSince1970:start_date]; + NSDate *end_date_nsdate = [NSDate dateWithTimeIntervalSince1970:end_date]; + + HKQuantityType *hk_quantity_type; + switch (quantity_type) { + case QUANTITY_TYPE_STEP_COUNT: + hk_quantity_type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierStepCount]; + break; + case QUANTITY_TYPE_ACTIVE_ENERGY_BURNED: + hk_quantity_type = [HKQuantityType quantityTypeForIdentifier:HKQuantityTypeIdentifierActiveEnergyBurned]; + break; + case QUANTITY_TYPE_UNKNOWN: + default: + NSLog(@"Unknown quantity type"); + return ERR_INVALID_PARAMETER; + } + + NSPredicate *predicate = [HKQuery predicateForSamplesWithStartDate:start_date_nsdate endDate:end_date_nsdate options:HKQueryOptionNone]; + + HKStatisticsQuery *query = [[HKStatisticsQuery alloc] initWithQuantityType:hk_quantity_type quantitySamplePredicate:predicate options:HKStatisticsOptionCumulativeSum completionHandler:^(HKStatisticsQuery *query, HKStatistics *result, NSError *error) { + NSLog(@"HealthKit query completed."); + + if (error) { + NSLog(@"Error while querying health data: %@", error); + emit_signal("statistics_query_failed", quantity_type, error.code); + return; + } + + HKQuantity *quantity = [result sumQuantity]; + double value = [quantity doubleValueForUnit:[HKUnit countUnit]]; + + emit_signal("statistics_query_completed", quantity_type, value); + }]; + + [_health_store executeQuery:query]; + NSLog(@"HealthKit query executed."); + + return OK; +} + +HealthKit::HealthKit() { + ERR_FAIL_COND(_instance != NULL); + _instance = this; + + NSLog(@"Creating HealthStore..."); + if (is_health_data_available()) { + _health_store = [[HKHealthStore alloc] init]; + NSLog(@"HealthStore created."); + } else { + NSLog(@"HealthKit is not available"); + NSLog(@"HealthStore creation failed."); + } +} + +HealthKit::~HealthKit() { +} diff --git a/plugins/healthkit/healthkit_module.cpp b/plugins/healthkit/healthkit_module.cpp new file mode 100644 index 0000000..cda904b --- /dev/null +++ b/plugins/healthkit/healthkit_module.cpp @@ -0,0 +1,54 @@ +/*************************************************************************/ +/* healthkit_module.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "healthkit_module.h" + +#include "core/version.h" + +#if VERSION_MAJOR == 4 +#include "core/config/engine.h" +#else +#include "core/engine.h" +#endif + +#include "healthkit.h" + +HealthKit* healthKit; + +void register_healthkit_types() { + healthKit = memnew(HealthKit); + Engine::get_singleton()->add_singleton(Engine::Singleton("HealthKit", healthKit)); +} + +void unregister_healthkit_types() { + if (healthKit) { + memdelete(healthKit); + } +} diff --git a/plugins/healthkit/healthkit_module.h b/plugins/healthkit/healthkit_module.h new file mode 100644 index 0000000..b639962 --- /dev/null +++ b/plugins/healthkit/healthkit_module.h @@ -0,0 +1,32 @@ +/*************************************************************************/ +/* healthkit_module.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +void register_healthkit_types(); +void unregister_healthkit_types(); diff --git a/scripts/generate_headers.sh b/scripts/generate_headers.sh index f2610a7..9fdc53e 100755 --- a/scripts/generate_headers.sh +++ b/scripts/generate_headers.sh @@ -1,4 +1,5 @@ #!/bin/bash + if [[ "$1" == "3.x" ]]; then cd ./godot && \ diff --git a/scripts/generate_static_library.sh b/scripts/generate_static_library.sh index 972bc6c..71f697b 100755 --- a/scripts/generate_static_library.sh +++ b/scripts/generate_static_library.sh @@ -1,4 +1,5 @@ #!/bin/bash + set -e # Compile static libraries @@ -15,4 +16,4 @@ scons target=$2 arch=x86_64 simulator=yes plugin=$1 version=$3 lipo -create "./bin/lib$1.x86_64-simulator.$2.a" \ "./bin/lib$1.armv7-ios.$2.a" \ "./bin/lib$1.arm64-ios.$2.a" \ - -output "./bin/$1.$2.a" \ No newline at end of file + -output "./bin/$1.$2.a" diff --git a/scripts/generate_xcframework.sh b/scripts/generate_xcframework.sh index 67b97e9..dea2c97 100755 --- a/scripts/generate_xcframework.sh +++ b/scripts/generate_xcframework.sh @@ -1,4 +1,5 @@ #!/bin/bash + set -e # Compile static libraries diff --git a/scripts/release_static_library.sh b/scripts/release_static_library.sh index 80758b8..4e075b9 100755 --- a/scripts/release_static_library.sh +++ b/scripts/release_static_library.sh @@ -18,4 +18,4 @@ mkdir ./bin/release for lib in $GODOT_PLUGINS; do mkdir ./bin/release/${lib} mv ./bin/${lib}.{release,debug}.a ./bin/release/${lib} -done \ No newline at end of file +done diff --git a/scripts/release_xcframework.sh b/scripts/release_xcframework.sh index dfd4c7c..17d5933 100755 --- a/scripts/release_xcframework.sh +++ b/scripts/release_xcframework.sh @@ -1,4 +1,5 @@ #!/bin/bash + set -e GODOT_PLUGINS="gamecenter inappstore icloud camera arkit apn photo_picker"