首先,我要感谢您抽出宝贵时间提供帮助!请注意,kv 文件由于长度容量而被缩短。
无论如何,我正在尝试使用 kivy/python 打包一个 apk。该应用程序在我的 Macbook、Linux VM 和我的 android 设备(Samsung Galaxy S6 Edge)上的 KivyLauncher 上运行良好。目前,我使用的唯一模块是基于 kivy 或 sqlite3(我在 buildozer.spec 中指定)。我正在用 buildozer 和 cython v0.20 编译 apk。下面是我的 main.py、kv 文件、buildozer.spec 和 logcat。
这是我的 main.py:
from kivy.app import App
from kivy.core.audio import SoundLoader
from kivy.uix.widget import Widget
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.screenmanager import ScreenManager, Screen
from os import getenv
from kivy.logger import Logger
import sqlite3
import sys
sys.platform = 'linux2'
Logger.info('title: This is a info message.')
Logger.debug('title: This is a debug message.')
try:
raise Exception('bleh')
except Exception:
Logger.exception('Something happened!')
class WelcomeScreen(Screen):
pass
class MainScreen(Screen):
pass
class ShowkerLotScreen(Screen):
spotsAvailable = "**"
def updateSpots(self, text, *args, **kwargs):
spotsAvailable = self.ids['spotsAvailableLabel']
conn = sqlite3.connect("testDB.db")
c = conn.cursor()
c.execute('SELECT * FROM Parking_Lot')
table = c.fetchall()
for row in table:
if row[1] == text:
spotsAvailable.text = str(row[2])
print("This lot has ", spotsAvailable.text, "spots available.")
conn.close()
class CantrellLotScreen(Screen):
spotsAvailable = "**"
def updateSpots(self, text, *args, **kwargs):
spotsAvailable = self.ids['spotsAvailableLabel']
conn = sqlite3.connect("testDB.db")
c = conn.cursor()
c.execute('SELECT * FROM Parking_Lot')
table = c.fetchall()
for row in table:
if row[1] == text:
spotsAvailable.text = str(row[2])
print("This lot has ", spotsAvailable.text, "spots available.")
conn.close()
class GraceLotScreen(Screen):
spotsAvailable = "**"
def updateSpots(self, text, *args, **kwargs):
spotsAvailable = self.ids['spotsAvailableLabel']
conn = sqlite3.connect("testDB.db")
c = conn.cursor()
c.execute('SELECT * FROM Parking_Lot')
table = c.fetchall()
for row in table:
if row[1] == text:
spotsAvailable.text = str(row[2])
print("This lot has ", spotsAvailable.text, "spots available.")
conn.close()
class ForbesLotScreen(Screen):
spotsAvailable = "**"
def updateSpots(self, text, *args, **kwargs):
spotsAvailable = self.ids['spotsAvailableLabel']
conn = sqlite3.connect("testDB.db")
c = conn.cursor()
c.execute('SELECT * FROM Parking_Lot')
table = c.fetchall()
for row in table:
if row[1] == text:
spotsAvailable.text = str(row[2])
print("This lot has ", spotsAvailable.text, "spots available.")
conn.close()
class ParkJMUApp(App):
pass
if __name__ == "__main__":
ParkJMUApp().run()
这是我的kv文件:
#:import Button kivy.uix.button
#:import Layout kivy.uix.layout
#:import ScrollView kivy.uix.scrollview
#:import Label kivy.uix.label
#Format for the parking lot buttons
<SButton@Button>
size_hint_y: None
height: 325
font_size: '20dp'
text_size: self.width/.8, None
valign: 'middle'
halign: 'center'
#Instantiate a screen manager and resulting screens
ScreenManager:
id: screen_manager
#Create the new screens
WelcomeScreen:
id: welcome_screen
name: 'WelcomeScreen'
manage: screen_manager
MainScreen:
id: main_screen
name: 'MainScreen'
manager: screen_manager
ShowkerLotScreen:
id: showker_lot_screen
name: 'ShowkerLotScreen'
manager: screen_manager
CantrellLotScreen:
id: cantrell_lot_screen
name: 'CantrellLotScreen'
manager: screen_manager
GraceLotScreen:
id: grace_lot_screen
name: 'GraceLotScreen'
manager: screen_manager
ForbesLotScreen:
id: forbes_lot_screen
name: 'ForbesLotScreen'
manager: screen_manager
<WelcomeScreen>
FloatLayout:
orientation: 'vertical'
canvas.before:
Rectangle:
size: self.size
source: 'images/Background.png'
Label:
text_size: root.width, None
text: "Welcome to ParkJMU"
SButton:
text: "Click to Smart Park!"
on_press: root.manager.current = 'MainScreen'
<MainScreen>
FloatLayout:
orientation: 'vertical'
canvas.before:
Rectangle:
size: self.size
source: 'images/Background.png'
Label:
text: 'Parking Lot:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/3.7, root.height/2.3
Widget:
BoxLayout:
size: root.width/1.25, root.height/2.8
pos: root.width/10, root.height/1.9
ScrollView:
id: scrollview2
old_y: [1, ] * 10
on_scroll_y:
self.old_y.append(self.scroll_y)
self.old_y.pop(0)
BoxLayout:
size_hint_y: None
height: grid2.minimum_height
GridLayout:
id: grid2
cols: 1
SButton:
text: 'Champions Drive\n(Zane Showker)'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'ShowkerLotScreen'
SButton:
text: 'Cantrell Ave\n(Student Success Center)'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'CantrellLotScreen'
SButton:
text: 'Grace Street\n(Student Success Center)'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'GraceLotScreen'
SButton:
text: 'Warsaw Ave\n(Forbes)'
on_press:
root.manager.transition.direction = 'left'
root.manager.current = 'ForbesLotScreen'
Label:
text: 'Spots Available:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/4.2, -root.height/20
Widget:
BoxLayout:
size: root.width/1.25, 325
pos: root.width/10, root.height/3.8
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
size: self.size
pos: root.width/10, root.height/4
Label:
text: '23'
color: 0,0,0,1
font_size: '45dp'
text_size: self.width/.8, None
halign: 'center'
SButton:
text: 'Refresh'
#on_press: root.store_minute(self.text)
<ShowkerLotScreen>
FloatLayout:
orientation: 'vertical'
canvas.before:
Rectangle:
size: self.size
source: 'images/Background.png'
Button:
pos_hint: {'x': 0, 'top': 1}
size_hint_y: None
height: 105
size_hint_x: None
width: 250
text_size: self.width/1.75, None
font_size: '12dp'
text: 'Back'
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'MainScreen'
Label:
text: 'Lot Section:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/3.7, root.height/2.3
Widget:
BoxLayout:
size: root.width/1.25, root.height/2.8
pos: root.width/10, root.height/1.9
ScrollView:
id: scrollview2
old_y: [1, ] * 10
on_scroll_y:
self.old_y.append(self.scroll_y)
self.old_y.pop(0)
BoxLayout:
size_hint_y: None
height: grid2.minimum_height
GridLayout:
id: grid2
cols: 1
SButton:
text: 'C11'
id: C11
on_press: root.updateSpots('C11')
SButton:
text: 'D2'
id: D2
on_press: root.updateSpots('D2')
SButton:
text: 'D3'
on_press: root.updateSpots('D3')
SButton:
text: 'F'
on_press: root.updateSpots('F')
Label:
text: 'Spots Available:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/4.2, -root.height/20
Widget:
BoxLayout:
size: root.width/1.25, 325
pos: root.width/10, root.height/3.8
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
size: self.size
pos: root.width/10, root.height/4
Label:
id: spotsAvailableLabel
text: 'Choose a Section'
color: 0,0,0,1
font_size: '45dp'
text_size: self.width/.8, None
halign: 'center'
SButton:
text: 'Refresh'
<CantrellLotScreen>
FloatLayout:
orientation: 'vertical'
canvas.before:
Rectangle:
size: self.size
source: 'images/Background.png'
Button:
pos_hint: {'x': 0, 'top': 1}
size_hint_y: None
height: 105
size_hint_x: None
width: 250
text_size: self.width/1.75, None
font_size: '12dp'
text: 'Back'
on_press:
root.manager.transition.direction = 'right'
root.manager.current = 'MainScreen'
Label:
text: 'Lot Section:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/3.7, root.height/2.3
Widget:
BoxLayout:
size: root.width/1.25, root.height/2.8
pos: root.width/10, root.height/1.9
ScrollView:
id: scrollview2
old_y: [1, ] * 10
on_scroll_y:
self.old_y.append(self.scroll_y)
self.old_y.pop(0)
BoxLayout:
size_hint_y: None
height: grid2.minimum_height
GridLayout:
id: grid2
cols: 1
SButton:
text: 'C11'
id: C11
on_press: root.updateSpots('C11')
SButton:
text: 'D2'
id: D2
on_press: root.updateSpots('D2')
SButton:
text: 'D3'
on_press: root.updateSpots('D3')
SButton:
text: 'F'
on_press: root.updateSpots('F')
Label:
text: 'Spots Available:'
font_size: '20dp'
bold: 1
color: [1,1,1,1]
pos: -root.width/4.2, -root.height/20
Widget:
BoxLayout:
size: root.width/1.25, 325
pos: root.width/10, root.height/3.8
canvas:
Color:
rgba: 1,1,1,1
Rectangle:
size: self.size
pos: root.width/10, root.height/4
Label:
id: spotsAvailableLabel
text: 'Choose a Section'
color: 0,0,0,1
font_size: '45dp'
text_size: self.width/.8, None
halign: 'center'
SButton:
text: 'Refresh'
这是我的 buildozer.spec:
[app]
# (str) Title of your application
title = ParkJMU
# (str) Package name
package.name = parkjmu
# (str) Package domain (needed for android/ios packaging)
package.domain = org.test
# (str) Source code where the main.py live
source.dir = .
# (list) Source files to include (let empty to include all the files)
source.include_exts = py,png,kv,db
# (list) Source files to exclude (let empty to not exclude anything)
source.exclude_exts =
# (list) List of directory to exclude (let empty to not exclude anything)
source.exclude_dirs = bin
# (list) List of exclusions using pattern matching
# source.exclude_patterns = license,images/*/*.jpg
# (str) Application versioning (method 1)
# version.regex = __version__ = ['"](.*)['"]
# version.filename = %(source.dir)s/main.py
# (str) Application versioning (method 2)
version = 1.4
# (list) Application requirements
# comma seperated e.g. requirements = sqlite3,kivy
requirements = kivy,sqlite3,pil,cymunk,pygame,plyer,android
# (str) Custom source folders for requirements
# Sets custom source for any requirements with recipes
# requirements.source.kivy = ../../kivy
# (list) Garden requirements
# garden_requirements =
# (str) Presplash of the application
# presplash.filename = ./images/Background.png
# (str) Icon of the application
# icon.filename = %(source.dir)s/data/icon.png
# (str) Supported orientation (one of landscape, portrait or all)
orientation = all
# (bool) Indicate if the application should be fullscreen or not
fullscreen = 1
#
# Android specific
#
# (list) Permissions
android.permissions = INTERNET,LOCATION_HARDWARE,WRITE_SECURE_SETTINGS,WRITE_SETTINGS
# (int) Android API to use
#android.api = 18
# (int) Minimum API required
#android.minapi = 8
# (int) Android SDK version to use
#android.sdk = 23
# (str) Android NDK version to use
#android.ndk = 9d
# (bool) Use --private data storage (True) or --dir public storage (False)
#android.private_storage = True
# (str) Android NDK directory (if empty, it will be automatically downloaded.)
#android.ndk_path =
# (str) Android SDK directory (if empty, it will be automatically downloaded.)
#android.sdk_path =
# (str) ANT directory (if empty, it will be automatically downloaded.)
#android.ant_path =
# (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
#android.p4a_dir =
# (list) python-for-android whitelist
#android.p4a_whitelist =
# (str) Android entry point, default is ok for Kivy-based app
#android.entrypoint = org.renpy.android.PythonActivity
# (list) List of Java .jar files to add to the libs so that pyjnius can access
# their classes. Don't add jars that you do not need, since extra jars can slow
# down the build process. Allows wildcards matching, for example:
# OUYA-ODK/libs/*.jar
#android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
# (list) List of Java files to add to the android project (can be java or a
# directory containing the files)
#android.add_src =
# (str) python-for-android branch to use, if not master, useful to try
# not yet merged features.
#android.branch = master
# (str) OUYA Console category. Should be one of GAME or APP
# If you leave this blank, OUYA support will not be enabled
#android.ouya.category = GAME
# (str) Filename of OUYA Console icon. It must be a 732x412 png image.
#android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
# (str) XML file to include as an intent filters in <activity> tag
#android.manifest.intent_filters =
# (list) Android additionnal libraries to copy into libs/armeabi
#android.add_libs_armeabi = libs/android/*.so
#android.add_libs_armeabi_v7a = libs/android-v7/*.so
#android.add_libs_x86 = libs/android-x86/*.so
#android.add_libs_mips = libs/android-mips/*.so
# (bool) Indicate whether the screen should stay on
# Don't forget to add the WAKE_LOCK permission if you set this to True
#android.wakelock = False
# (list) Android application meta-data to set (key=value format)
#android.meta_data =
# (list) Android library project to add (will be added in the
# project.properties automatically.)
#android.library_references =
#
# iOS specific
#
# (str) Name of the certificate to use for signing the debug version
# Get a list of available identities: buildozer ios list_identities
#ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
# (str) Name of the certificate to use for signing the release version
#ios.codesign.release = %(ios.codesign.debug)s
[buildozer]
# (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
log_level = 2
# (int) Display warning if buildozer is run as root (0 = False, 1 = True)
warn_on_root = 1
# -----------------------------------------------------------------------------
# List as sections
#
# You can define all the "list" as [section:key].
# Each line will be considered as a option to the list.
# Let's take [app] / source.exclude_patterns.
# Instead of doing:
#
#[app]
#source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
#
# This can be translated into:
#
#[app:source.exclude_patterns]
#license
#data/audio/*.wav
#data/images/original/*
#
# -----------------------------------------------------------------------------
# Profiles
#
# You can extend section / key with a profile
# For example, you want to deploy a demo version of your application without
# HD content. You could first change the title to add "(demo)" in the name
# and extend the excluded directories to remove the HD content.
#
#[app@demo]
#title = My Application (demo)
#
#[app:source.exclude_patterns@demo]
#images/hd/*
#
# Then, invoke the command line with the "demo" profile:
#
#buildozer --profile demo android debug
最后,logcat:
I/ActivityManager( 3627): Start proc 21619:org.test.parkjmu:python/u0a477 for activity org.test.parkjmu/org.renpy.android.PythonActivity
V/python (21619): metadata fullscreen is1
E/art (21619): dlopen("/data/data/org.test.parkjmu/files/lib/python2.7/lib-dynload/_imaging.so", RTLD_LAZY) failed: dlopen failed: library "/data/data/org.test.parkjmu/files/lib/python2.7/lib-dynload/_imaging.so" not found
I/python (21619): Starting audio thread
I/python (21619): Initialize Python for Android
I/python (21619): ['/data/data/org.test.parkjmu/files/lib/python2.7/site-packages', '/data/data/org.test.parkjmu/files/lib/site-python']
I/python (21619): Android path ['/data/data/org.test.parkjmu/files/lib/python27.zip', '/data/data/org.test.parkjmu/files/lib/python2.7', '/data/data/org.test.parkjmu/files/lib/python2.7/lib-dynload', '/data/data/org.test.parkjmu/files/lib/python2.7/site-packages', '/data/data/org.test.parkjmu/files', '/data/data/org.test.parkjmu/files/lib/python2.7/site-packages/PIL', '/data/data/org.test.parkjmu/files/_applibs']
I/python (21619): Android kivy bootstrap done. __name__ is __main__
I/python (21619): Run user program, change dir and execute main.py
I/python (21619): [INFO ] [Logger ] Record log in /data/data/org.test.parkjmu/files/.kivy/logs/kivy_15-10-20_3.txt
I/python (21619): [INFO ] [Kivy ] v1.9.0
I/python (21619): [INFO ] [Python ] v2.7.2 (default, Oct 15 2015, 10:33:53)
I/python (21619): [GCC 4.8]
I/python (21619): [INFO ] [Factory ] 173 symbols loaded
I/python (21619): /data/data/org.test.parkjmu/files/lib/python2.7/site-packages/kivy/core/image/img_pygame.py:13: RuntimeWarning: import cdrom: No module named cdrom
I/python (21619): (ImportError: No module named cdrom)
I/python (21619): [INFO ] [Image ] Providers: img_tex, img_dds, img_gif, img_pygame, img_pil (img_ffpyplayer ignored)
I/python (21619): [INFO ] [Audio ] Providers: audio_pygame (audio_pygst, audio_ffpyplayer ignored)
I/python (21619): [INFO ] [Text ] Provider: pygame
I/python (21619): [INFO ] [title ] This is a info message.
I/python (21619): [ERROR ] Something happened!
I/python (21619): Traceback (most recent call last):
I/python (21619): File "/home/sungrj/Documents/ParkJMU/.buildozer/android/app/main.py", line 18, in <module>
I/python (21619): Exception: bleh
I/python (21619): [INFO ] [Window ] Provider: pygame
I/python (21619): [INFO ] [GL ] OpenGL version <OpenGL ES 3.1>
I/python (21619): [INFO ] [GL ] OpenGL vendor <ARM>
I/python (21619): [INFO ] [GL ] OpenGL renderer <Mali-T760>
I/python (21619): [INFO ] [GL ] OpenGL parsed version: 3, 1
I/python (21619): [INFO ] [GL ] Texture max size <8192>
I/python (21619): [INFO ] [GL ] Texture max units <16>
I/python (21619): [INFO ] [Support ] Android install hooks
I/python (21619): [INFO ] [Window ] virtual keyboard not allowed, single mode, not docked
I/python (21619): [INFO ] [OSC ] using <thread> for socket
I/python (21619): [INFO ] [Base ] Start application main loop
I/python (21619): [INFO ] [Android ] found 17 joystick
I/python (21619): [INFO ] [Android ] create joystick <0>
I/python (21619): [INFO ] [Android ] discard joystick <0> cause no button
I/python (21619): [INFO ] [Android ] create joystick <1>
I/python (21619): [INFO ] [Android ] create joystick <2>
I/python (21619): [INFO ] [Android ] create joystick <3>
I/python (21619): [INFO ] [Android ] create joystick <4>
I/python (21619): [INFO ] [Android ] create joystick <5>
I/python (21619): [INFO ] [Android ] create joystick <6>
I/python (21619): [INFO ] [Android ] create joystick <7>
I/python (21619): [INFO ] [Android ] create joystick <8>
I/python (21619): [INFO ] [Android ] create joystick <9>
I/python (21619): [INFO ] [Android ] create joystick <10>
I/python (21619): [INFO ] [Android ] create joystick <11>
I/python (21619): [INFO ] [Android ] create joystick <12>
I/python (21619): [INFO ] [Android ] create joystick <13>
I/python (21619): [INFO ] [Android ] create joystick <14>
I/python (21619): [INFO ] [Android ] create joystick <15>
I/python (21619): [INFO ] [Android ] create joystick <16>
I/python (21619): [INFO ] [Android ] Must go into sleep mode, check the app
I/python (21619): [INFO ] [Android ] App doesn't support pause mode, stop.
I/python (21619): [INFO ] [Base ] Leaving application in progress...
I/python (21619): Python for android ended.
I/ActivityManager( 3627): Process org.test.parkjmu:python (pid 21619)(adj 1) has died(61,277)
如果您需要我的其他任何东西,请告诉我。如果您在打包 apk 时需要日志,请提供如何最好地执行此操作的步骤。