diff --git a/Sources/armory/logicnode/SetVibrateNode.hx b/Sources/armory/logicnode/SetVibrateNode.hx new file mode 100644 index 00000000..996be15d --- /dev/null +++ b/Sources/armory/logicnode/SetVibrateNode.hx @@ -0,0 +1,16 @@ +// Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists. + +package armory.logicnode; +import kha.System; + +class SetVibrateNode extends LogicNode { + + public function new(tree: LogicTree) { + super(tree); + } + + override function run(from: Int) { + if (inputs[1].get() > 0) System.vibrate(inputs[1].get()); + runOutput(0); + } +} diff --git a/blender/arm/logicnode/native/LN_set_vibrate.py b/blender/arm/logicnode/native/LN_set_vibrate.py new file mode 100644 index 00000000..93672aca --- /dev/null +++ b/blender/arm/logicnode/native/LN_set_vibrate.py @@ -0,0 +1,19 @@ +from arm.logicnode.arm_nodes import * +import arm.utils + +class SetVibrateNode(ArmLogicTreeNode): + """Pulses the vibration hardware on the device for time in milliseconds, if such hardware exists.""" + bl_idname = 'LNSetVibrateNode' + bl_label = 'Set Vibrate' + arm_version = 1 + + def init(self, context): + super(SetVibrateNode, self).init(context) + self.add_input('ArmNodeSocketAction', 'In') + self.add_input('NodeSocketInt', 'Milliseconds') + self.inputs[-1].default_value = 100 + self.add_output('ArmNodeSocketAction', 'Out') + # Add permission for target android + arm.utils.add_permission_target_android(arm.utils.PermissionName.VIBRATE) + +add_node(SetVibrateNode, category=PKG_AS_CATEGORY, section='Native') diff --git a/blender/arm/props.py b/blender/arm/props.py index 7f4f76a6..ee130430 100755 --- a/blender/arm/props.py +++ b/blender/arm/props.py @@ -20,6 +20,9 @@ def init_properties(): bpy.types.World.arm_project_package = StringProperty(name="Package", description="Package name for scripts", default="arm", update=assets.invalidate_compiler_cache) bpy.types.World.arm_project_version = StringProperty(name="Version", description="Exported project version", default="1.0", update=assets.invalidate_compiler_cache) bpy.types.World.arm_project_bundle = StringProperty(name="Bundle", description="Exported project bundle", default="", update=assets.invalidate_compiler_cache) + bpy.types.World.arm_project_android_sdk_compile = IntProperty(name="Compile Version SDK", description="Compile Android SDK Version", default=29, min=26, max=30, update=assets.invalidate_compiler_cache) + bpy.types.World.arm_project_android_sdk_min = IntProperty(name="Minimal Version SDK", description="Minimal Version Android SDK", default=14, min=14, max=30, update=assets.invalidate_compiler_cache) + bpy.types.World.arm_project_android_sdk_target = IntProperty(name="Target Version SDK", description="Target Version Android SDK", default=29, min=26, max=30, update=assets.invalidate_compiler_cache) bpy.types.World.arm_project_icon = StringProperty(name="Icon (PNG)", description="Exported project icon, must be a PNG image", default="", subtype="FILE_PATH", update=assets.invalidate_compiler_cache) bpy.types.World.arm_project_root = StringProperty(name="Root", description="Set root folder for linked assets", default="", subtype="DIR_PATH", update=assets.invalidate_compiler_cache) bpy.types.World.arm_physics = EnumProperty( diff --git a/blender/arm/props_exporter.py b/blender/arm/props_exporter.py index 855f9d6e..2b19a543 100644 --- a/blender/arm/props_exporter.py +++ b/blender/arm/props_exporter.py @@ -122,6 +122,32 @@ class ArmExporterListItem(bpy.types.PropertyGroup): ('webgl', 'WebGL2', 'webgl')], name="Graphics API", default='webgl', description='Based on currently selected target', update=update_gapi_html5) +class ArmExporterAndroidPermissionListItem(bpy.types.PropertyGroup): + arm_android_permissions: EnumProperty( + items = [('ACCESS_COARSE_LOCATION ', 'Access Coarse Location', 'Allows an app to access approximate location'), + ('ACCESS_NETWORK_STATE', 'Access Network State', 'Allows applications to access information about networks'), + ('ACCESS_FINE_LOCATION', 'Access Fine Location', 'Allows an app to access precise location'), + ('ACCESS_WIFI_STATE', 'Access Wi-Fi State', 'Allows applications to access information about Wi-Fi networks'), + ('BLUETOOTH', 'Bluetooth', 'Allows applications to connect to paired bluetooth devices'), + ('BLUETOOTH_ADMIN', 'Bluetooth Admin', 'Allows applications to discover and pair bluetooth devices'), + ('CAMERA', 'Camera', 'Required to be able to access the camera device'), + ('EXPAND_STATUS_BAR', 'Expand Status Bar', 'Allows an application to expand or collapse the status bar'), + ('FOREGROUND_SERVICE', 'Foreground Service', 'Allows a regular application to use Service.startForeground'), + ('GET_ACCOUNTS', 'Get Accounts', 'Allows access to the list of accounts in the Accounts Service'), + ('INTERNET', 'Internet', 'Allows applications to open network sockets'), + ('READ_EXTERNAL_STORAGE', 'Read External Storage', 'Allows an application to read from external storage.'), + ('VIBRATE', 'Vibrate', 'Allows access to the vibrator'), + ('WRITE_EXTERNAL_STORAGE', 'Write External Storage', 'Allows an application to write to external storage')], + name="Permission", default='VIBRATE', description='Android Permission') + +class ArmExporterAndroidAbiListItem(bpy.types.PropertyGroup): + arm_android_abi: EnumProperty( + items = [('arm64-v8a', 'arm64-v8a', 'This ABI is for ARMv8-A based CPUs, which support the 64-bit AArch64 architecture'), + ('armeabi-v7a', 'armeabi-v7a', 'This ABI is for 32-bit ARM-based CPUs'), + ('x86', 'x86', 'This ABI is for CPUs supporting the instruction set commonly known as x86, i386, or IA-32'), + ('x86_64', 'x86_64', 'This ABI is for CPUs supporting the instruction set commonly referred to as x86-64')], + name="Android ABI", default='arm64-v8a', description='Android ABI') + class ARM_UL_ExporterList(bpy.types.UIList): def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): # We could write some code to decide which icon to use here... @@ -139,6 +165,40 @@ class ARM_UL_ExporterList(bpy.types.UIList): layout.alignment = 'CENTER' layout.label(text="", icon = custom_icon) +class ARM_UL_Exporter_AndroidPermissionList(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # We could write some code to decide which icon to use here... + custom_icon = 'DOT' + + # Make sure your code supports all 3 layout types + if self.layout_type in {'DEFAULT', 'COMPACT'}: + row = layout.row() + row.prop(item, "name", text="", emboss=False, icon=custom_icon) + col = row.column() + col.alignment = 'RIGHT' + col.label(text=item.arm_android_permissions) + + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon = custom_icon) + +class ARM_UL_Exporter_AndroidAbiList(bpy.types.UIList): + def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index): + # We could write some code to decide which icon to use here... + custom_icon = 'DOT' + + # Make sure your code supports all 3 layout types + if self.layout_type in {'DEFAULT', 'COMPACT'}: + row = layout.row() + row.prop(item, "name", text="", emboss=False, icon=custom_icon) + col = row.column() + col.alignment = 'RIGHT' + col.label(text=item.arm_android_abi) + + elif self.layout_type in {'GRID'}: + layout.alignment = 'CENTER' + layout.label(text="", icon = custom_icon) + class ArmExporterListNewItem(bpy.types.Operator): # Add a new item to the list bl_idname = "arm_exporterlist.new_item" @@ -218,6 +278,76 @@ class ArmExporterListMoveItem(bpy.types.Operator): return{'CANCELLED'} return{'FINISHED'} +class ArmExporter_AndroidPermissionListNewItem(bpy.types.Operator): + # Add a new item to the list + bl_idname = "arm_exporter_android_permission_list.new_item" + bl_label = "Add a new item" + + def execute(self, context): + mdata = bpy.data.worlds['Arm'] + mdata.arm_exporter_android_permission_list.add() + mdata.arm_exporter_android_permission_list_index = len(mdata.arm_exporter_android_permission_list) - 1 + return{'FINISHED'} + +class ArmExporter_AndroidPermissionListDeleteItem(bpy.types.Operator): + # Delete the selected item from the list + bl_idname = "arm_exporter_android_permission_list.delete_item" + bl_label = "Deletes an item" + + @classmethod + def poll(self, context): + """ Enable if there's something in the list """ + mdata = bpy.data.worlds['Arm'] + return len(mdata.arm_exporter_android_permission_list) > 0 + + def execute(self, context): + mdata = bpy.data.worlds['Arm'] + list = mdata.arm_exporter_android_permission_list + index = mdata.arm_exporter_android_permission_list_index + + list.remove(index) + + if index > 0: + index = index - 1 + + mdata.arm_exporter_android_permission_list_index = index + return{'FINISHED'} + +class ArmExporter_AndroidAbiListNewItem(bpy.types.Operator): + # Add a new item to the list + bl_idname = "arm_exporter_android_abi_list.new_item" + bl_label = "Add a new item" + + def execute(self, context): + mdata = bpy.data.worlds['Arm'] + mdata.arm_exporter_android_abi_list.add() + mdata.arm_exporter_android_abi_list_index = len(mdata.arm_exporter_android_abi_list) - 1 + return{'FINISHED'} + +class ArmExporter_AndroidAbiListDeleteItem(bpy.types.Operator): + # Delete the selected item from the list + bl_idname = "arm_exporter_android_abi_list.delete_item" + bl_label = "Deletes an item" + + @classmethod + def poll(self, context): + """ Enable if there's something in the list """ + mdata = bpy.data.worlds['Arm'] + return len(mdata.arm_exporter_android_abi_list) > 0 + + def execute(self, context): + mdata = bpy.data.worlds['Arm'] + list = mdata.arm_exporter_android_abi_list + index = mdata.arm_exporter_android_abi_list_index + + list.remove(index) + + if index > 0: + index = index - 1 + + mdata.arm_exporter_android_abi_list_index = index + return{'FINISHED'} + class ArmExporterSpecialsMenu(bpy.types.Menu): bl_label = "More" bl_idname = "ARM_MT_ExporterListSpecials" @@ -268,23 +398,43 @@ class ArmExporterGpuProfileButton(bpy.types.Operator): def register(): bpy.utils.register_class(ArmExporterListItem) + bpy.utils.register_class(ArmExporterAndroidPermissionListItem) + bpy.utils.register_class(ArmExporterAndroidAbiListItem) bpy.utils.register_class(ARM_UL_ExporterList) + bpy.utils.register_class(ARM_UL_Exporter_AndroidPermissionList) + bpy.utils.register_class(ARM_UL_Exporter_AndroidAbiList) bpy.utils.register_class(ArmExporterListNewItem) bpy.utils.register_class(ArmExporterListDeleteItem) bpy.utils.register_class(ArmExporterListMoveItem) + bpy.utils.register_class(ArmExporter_AndroidPermissionListNewItem) + bpy.utils.register_class(ArmExporter_AndroidPermissionListDeleteItem) + bpy.utils.register_class(ArmExporter_AndroidAbiListNewItem) + bpy.utils.register_class(ArmExporter_AndroidAbiListDeleteItem) bpy.utils.register_class(ArmExporterSpecialsMenu) bpy.utils.register_class(ArmExporterGpuProfileButton) bpy.utils.register_class(ArmoryExporterOpenFolderButton) bpy.types.World.arm_exporterlist = CollectionProperty(type=ArmExporterListItem) bpy.types.World.arm_exporterlist_index = IntProperty(name="Index for my_list", default=0) + bpy.types.World.arm_exporter_android_permission_list = CollectionProperty(type=ArmExporterAndroidPermissionListItem) + bpy.types.World.arm_exporter_android_permission_list_index = IntProperty(name="Index for my_list", default=0) + bpy.types.World.arm_exporter_android_abi_list = CollectionProperty(type=ArmExporterAndroidAbiListItem) + bpy.types.World.arm_exporter_android_abi_list_index = IntProperty(name="Index for my_list", default=0) def unregister(): bpy.utils.unregister_class(ArmExporterListItem) + bpy.utils.unregister_class(ArmExporterAndroidPermissionListItem) + bpy.utils.unregister_class(ArmExporterAndroidAbiListItem) bpy.utils.unregister_class(ARM_UL_ExporterList) + bpy.utils.unregister_class(ARM_UL_Exporter_AndroidPermissionList) + bpy.utils.unregister_class(ARM_UL_Exporter_AndroidAbiList) bpy.utils.unregister_class(ArmExporterListNewItem) bpy.utils.unregister_class(ArmExporterListDeleteItem) bpy.utils.unregister_class(ArmExporterListMoveItem) + bpy.utils.unregister_class(ArmExporter_AndroidPermissionListNewItem) + bpy.utils.unregister_class(ArmExporter_AndroidPermissionListDeleteItem) + bpy.utils.unregister_class(ArmExporter_AndroidAbiListNewItem) + bpy.utils.unregister_class(ArmExporter_AndroidAbiListDeleteItem) bpy.utils.unregister_class(ArmExporterSpecialsMenu) bpy.utils.unregister_class(ArmExporterGpuProfileButton) bpy.utils.unregister_class(ArmoryExporterOpenFolderButton) diff --git a/blender/arm/props_ui.py b/blender/arm/props_ui.py index 16ffa403..86efc568 100644 --- a/blender/arm/props_ui.py +++ b/blender/arm/props_ui.py @@ -408,8 +408,8 @@ class ARM_PT_ArmoryExporterPanel(bpy.types.Panel): col = layout.column() col.prop(wrd, 'arm_project_name') col.prop(wrd, 'arm_project_package') - col.prop(wrd, 'arm_project_version') col.prop(wrd, 'arm_project_bundle') + col.prop(wrd, 'arm_project_version') col.prop(wrd, 'arm_project_icon') col.prop(wrd, 'arm_dce') col.prop(wrd, 'arm_compiler_inline') @@ -418,6 +418,126 @@ class ARM_PT_ArmoryExporterPanel(bpy.types.Panel): col.prop(wrd, 'arm_asset_compression') col.prop(wrd, 'arm_single_data_file') +class ARM_PT_ArmoryExporterAndroidSettingsPanel(bpy.types.Panel): + bl_label = "Android Settings" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = { 'DEFAULT_CLOSED' } + bl_parent_id = "ARM_PT_ArmoryExporterPanel" + + @classmethod + def poll(cls, context): + wrd = bpy.data.worlds['Arm'] + is_check = False + for item in wrd.arm_exporterlist: + is_check = item.arm_project_target == 'android-hl' + if is_check: + break + return is_check + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + wrd = bpy.data.worlds['Arm'] + if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0: + item = wrd.arm_exporterlist[wrd.arm_exporterlist_index] + layout.enabled = item.arm_project_target == 'android-hl' + # Options + row = layout.row() + row.prop(wrd, 'arm_winorient') + row = layout.row() + row.prop(wrd, 'arm_project_android_sdk_compile') + row = layout.row() + row.prop(wrd, 'arm_project_android_sdk_min') + row = layout.row() + row.prop(wrd, 'arm_project_android_sdk_target') + +class ARM_PT_ArmoryExporterAndroidPermissionsPanel(bpy.types.Panel): + bl_label = "Permissions" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = { 'DEFAULT_CLOSED' } + bl_parent_id = "ARM_PT_ArmoryExporterAndroidSettingsPanel" + + @classmethod + def poll(cls, context): + wrd = bpy.data.worlds['Arm'] + is_check = False + for item in wrd.arm_exporterlist: + is_check = item.arm_project_target == 'android-hl' + if is_check: + break + return is_check + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + wrd = bpy.data.worlds['Arm'] + if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0: + item = wrd.arm_exporterlist[wrd.arm_exporterlist_index] + layout.enabled = item.arm_project_target == 'android-hl' + # Permission + row = layout.row() + rows = 2 + if len(wrd.arm_exporter_android_permission_list) > 1: + rows = 4 + row.template_list("ARM_UL_Exporter_AndroidPermissionList", "The_List", wrd, "arm_exporter_android_permission_list", wrd, "arm_exporter_android_permission_list_index", rows=rows) + col = row.column(align=True) + col.operator("arm_exporter_android_permission_list.new_item", icon='ADD', text="") + col.operator("arm_exporter_android_permission_list.delete_item", icon='REMOVE', text="") + row = layout.row() + + if wrd.arm_exporter_android_permission_list_index >= 0 and len(wrd.arm_exporter_android_permission_list) > 0: + item = wrd.arm_exporter_android_permission_list[wrd.arm_exporter_android_permission_list_index] + row = layout.row() + row.prop(item, 'arm_android_permissions') + +class ARM_PT_ArmoryExporterAndroidAbiPanel(bpy.types.Panel): + bl_label = "Android ABI Filters" + bl_space_type = "PROPERTIES" + bl_region_type = "WINDOW" + bl_context = "render" + bl_options = { 'DEFAULT_CLOSED'} + bl_parent_id = "ARM_PT_ArmoryExporterAndroidSettingsPanel" + + @classmethod + def poll(cls, context): + wrd = bpy.data.worlds['Arm'] + is_check = False + for item in wrd.arm_exporterlist: + is_check = item.arm_project_target == 'android-hl' + if is_check: + break + return is_check + + def draw(self, context): + layout = self.layout + layout.use_property_split = True + layout.use_property_decorate = False + wrd = bpy.data.worlds['Arm'] + if wrd.arm_exporterlist_index >= 0 and len(wrd.arm_exporterlist) > 0: + item = wrd.arm_exporterlist[wrd.arm_exporterlist_index] + layout.enabled = item.arm_project_target == 'android-hl' + # ABIs + row = layout.row() + rows = 2 + if len(wrd.arm_exporter_android_abi_list) > 1: + rows = 4 + row.template_list("ARM_UL_Exporter_AndroidAbiList", "The_List", wrd, "arm_exporter_android_abi_list", wrd, "arm_exporter_android_abi_list_index", rows=rows) + col = row.column(align=True) + col.operator("arm_exporter_android_abi_list.new_item", icon='ADD', text="") + col.operator("arm_exporter_android_abi_list.delete_item", icon='REMOVE', text="") + row = layout.row() + + if wrd.arm_exporter_android_abi_list_index >= 0 and len(wrd.arm_exporter_android_abi_list) > 0: + item = wrd.arm_exporter_android_abi_list[wrd.arm_exporter_android_abi_list_index] + row = layout.row() + row.prop(item, 'arm_android_abi') + class ARM_PT_ArmoryProjectPanel(bpy.types.Panel): bl_label = "Armory Project" bl_space_type = "PROPERTIES" @@ -499,7 +619,6 @@ class ARM_PT_ProjectWindowPanel(bpy.types.Panel): layout.use_property_decorate = False wrd = bpy.data.worlds['Arm'] layout.prop(wrd, 'arm_winmode') - layout.prop(wrd, 'arm_winorient') layout.prop(wrd, 'arm_winresize') col = layout.column() col.enabled = wrd.arm_winresize @@ -1417,7 +1536,7 @@ class ARM_PT_BakePanel(bpy.types.Panel): row = layout.row(align=True) row.operator("tlm.remove_uv_selection") row = layout.row(align=True) - + class ArmGenLodButton(bpy.types.Operator): '''Automatically generate LoD levels''' @@ -2017,6 +2136,9 @@ def register(): bpy.utils.register_class(ARM_PT_MaterialBlendingPropsPanel) bpy.utils.register_class(ARM_PT_ArmoryPlayerPanel) bpy.utils.register_class(ARM_PT_ArmoryExporterPanel) + bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidSettingsPanel) + bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidPermissionsPanel) + bpy.utils.register_class(ARM_PT_ArmoryExporterAndroidAbiPanel) bpy.utils.register_class(ARM_PT_ArmoryProjectPanel) bpy.utils.register_class(ARM_PT_ProjectFlagsPanel) bpy.utils.register_class(ARM_PT_ProjectFlagsDebugConsolePanel) @@ -2081,6 +2203,9 @@ def unregister(): bpy.utils.unregister_class(ARM_PT_MaterialPropsPanel) bpy.utils.unregister_class(ARM_PT_MaterialBlendingPropsPanel) bpy.utils.unregister_class(ARM_PT_ArmoryPlayerPanel) + bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidAbiPanel) + bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidPermissionsPanel) + bpy.utils.unregister_class(ARM_PT_ArmoryExporterAndroidSettingsPanel) bpy.utils.unregister_class(ARM_PT_ArmoryExporterPanel) bpy.utils.unregister_class(ARM_PT_ArmoryProjectPanel) bpy.utils.unregister_class(ARM_PT_ProjectFlagsDebugConsolePanel) diff --git a/blender/arm/utils.py b/blender/arm/utils.py index 0132c05b..3ec760c7 100755 --- a/blender/arm/utils.py +++ b/blender/arm/utils.py @@ -15,7 +15,7 @@ from arm.lib.lz4 import LZ4 import arm.log as log import arm.make_state as state import arm.props_renderpath - +from enum import Enum, unique class NumpyEncoder(json.JSONEncoder): def default(self, obj): @@ -856,9 +856,38 @@ def check_default_props(): # Take blend file name wrd.arm_project_name = arm.utils.blend_name() +# Enum Permissions Name +class PermissionName(Enum): + ACCESS_COARSE_LOCATION = 'ACCESS_COARSE_LOCATION' + ACCESS_NETWORK_STATE = 'ACCESS_NETWORK_STATE' + ACCESS_FINE_LOCATION = 'ACCESS_FINE_LOCATION' + ACCESS_WIFI_STATE = 'ACCESS_WIFI_STATE' + BLUETOOTH = 'BLUETOOTH' + BLUETOOTH_ADMIN = 'BLUETOOTH_ADMIN' + CAMERA = 'CAMERA' + EXPAND_STATUS_BAR = 'EXPAND_STATUS_BAR' + FOREGROUND_SERVICE = 'FOREGROUND_SERVICE' + GET_ACCOUNTS = 'GET_ACCOUNTS' + INTERNET = 'INTERNET' + READ_EXTERNAL_STORAGE = 'READ_EXTERNAL_STORAGE' + VIBRATE = 'VIBRATE' + WRITE_EXTERNAL_STORAGE = 'WRITE_EXTERNAL_STORAGE' + +# Add permission for target android +def add_permission_target_android(permission_name_enum): + wrd = bpy.data.worlds['Arm'] + check = False + for item in wrd.arm_exporter_android_permission_list: + if (item.arm_android_permissions.upper() == str(permission_name_enum.value).upper()): + check = True + break + if not check: + wrd.arm_exporter_android_permission_list.add() + wrd.arm_exporter_android_permission_list[len(wrd.arm_exporter_android_permission_list) - 1].arm_android_permissions = str(permission_name_enum.value).upper() + def register(local_sdk=False): global use_local_sdk use_local_sdk = local_sdk def unregister(): - pass + pass \ No newline at end of file diff --git a/blender/arm/write_data.py b/blender/arm/write_data.py index 27f87fd0..c73f8c29 100755 --- a/blender/arm/write_data.py +++ b/blender/arm/write_data.py @@ -291,6 +291,36 @@ project.addSources('Sources'); khafile.write("project.targetOptions.android_native.package = '{0}';\n".format(arm.utils.safestr(bundle))) if wrd.arm_winorient != 'Multi': khafile.write("project.targetOptions.android_native.screenOrientation = '{0}';\n".format(wrd.arm_winorient.lower())) + # Android SDK Versions + khafile.write("project.targetOptions.android_native.compileSdkVersion = '{0}';\n".format(wrd.arm_project_android_sdk_compile)) + khafile.write("project.targetOptions.android_native.minSdkVersion = '{0}';\n".format(wrd.arm_project_android_sdk_min)) + khafile.write("project.targetOptions.android_native.targetSdkVersion = '{0}';\n".format(wrd.arm_project_android_sdk_target)) + # Permissions + if len(wrd.arm_exporter_android_permission_list) > 0: + perms = '' + for item in wrd.arm_exporter_android_permission_list: + perm = "'android.permission."+ item.arm_android_permissions +"'" + # Checking In + if perms.find(perm) == -1: + if len(perms) > 0: + perms = perms +', '+ perm + else: + perms = perm + if len(perms) > 0: + khafile.write("project.targetOptions.android_native.permissions = [{0}];\n".format(perms)) + # Android ABI Filters + if len(wrd.arm_exporter_android_abi_list) > 0: + abis = '' + for item in wrd.arm_exporter_android_abi_list: + abi = "'"+ item.arm_android_abi +"'" + # Checking In + if abis.find(abi) == -1: + if len(abis) > 0: + abis = abis +', '+ abi + else: + abis = abi + if len(abis) > 0: + khafile.write("project.targetOptions.android_native.abiFilters = [{0}];\n".format(abis)) elif state.target.startswith('ios'): bundle = 'org.armory3d.' + wrd.arm_project_package if wrd.arm_project_bundle == '' else wrd.arm_project_bundle khafile.write("project.targetOptions.ios.bundle = '{0}';\n".format(arm.utils.safestr(bundle)))