Python Kivy安卓应用在移动设备上运行APK后崩溃。

huangapple go评论113阅读模式
英文:

python kivy android app crashes after running apk on mobile device

问题

我正在尝试使用Kivy Python框架开发Android应用程序。该程序与远程MySQL数据库连接。代码的一部分(注册和登录页面)已在pyCharm中进行了测试,并且在运行良好。为了转换为Android应用程序,我在运行了命令buildozer android debug后,使用在Oracle VM VirtualBox上运行的Ubuntu 19.10操作系统获取了APK文件。但是,在运行命令buildozer android deploy run时,出现以下输出和错误消息,导致应用程序崩溃。

  1. > List of devices attached
  2. > ZX1PC222GV device
  3. > Run on ZX1PC222GV
  4. > Run '/home/nirmal/.buildozer/android/platform/android-sdk/platform-tools/adb shell am start -n org.test.kkfoodies/org.kivy.android.PythonActivity -a org.kivy.android.PythonActivity'
  5. > Cwd /home/nirmal/.buildozer/android/platform
  6. > Starting: Intent { act=org.kivy.android.PythonActivity
  7. cmp=org.test.kkfoodies/org.kivy.android.PythonActivity }
  8. > **Error type 3**
  9. > **Error: Activity class {org.test.kkfoodies/org.kivy.android.PythonActivity} does not exist.**
  10. > Application started

以下是我的buildozer.spec文件:

  1. [app]
  2. title = KK Foodies
  3. package.name = kkfoodies
  4. package.domain = org.test
  5. source.dir = .
  6. source.include_exts = py,png,jpg,kv,atlas
  7. version = 1.0
  8. requirements = python3,kivy
  9. orientation = portrait
  10. fullscreen = 0
  11. android.minapi = 21
  12. android.arch = armeabi-v7a
  13. [buildozer]
  14. log_level = 2
  15. warn_on_root = 1

这是Python代码文件的一部分:

  1. # ... 这里省略了代码的一部分 ...
  2. class LoginWindow(Screen):
  3. def __init__(self, **kwargs):
  4. super().__init__(**kwargs)
  5. self.db = DbCon()
  6. def validate_user(self):
  7. # ... 这里省略了代码的一部分 ...
  8. class RegisterWindow(Screen):
  9. def __init__(self, **kwargs):
  10. super().__init__(**kwargs)
  11. self.db2 = DbCon()
  12. def register_user(self):
  13. # ... 这里省略了代码的一部分 ...
  14. class FoodiesApp(App):
  15. def build(self):
  16. return ScreenManagement()
  17. if __name__ == "__main__":
  18. sa = FoodiesApp()
  19. sa.run()

如果你遇到了特定问题,请提供更多详细信息,我将尽力帮助你解决。

英文:

I was trying to develop an android app using the kivy python framework. The program connects with a remote mysql database. A part of the code (registration and login page) was tested in pyCharm and found to be working perfectly. For converting to an android app, Ubuntu 19.10 OS running on Oracle VM VirtualBox was used. APK file was obtained by running command buildozer android debug. But on running the command buildozer android deploy run, the following output with error message comes and app crashes.

> List of devices attached
> ZX1PC222GV device
> Run on ZX1PC222GV
> Run '/home/nirmal/.buildozer/android/platform/android-sdk/platform-tools/adb shell am start -n org.test.kkfoodies/org.kivy.android.PythonActivity -a org.kivy.android.PythonActivity'
> Cwd /home/nirmal/.buildozer/android/platform
> Starting: Intent { act=org.kivy.android.PythonActivity
cmp=org.test.kkfoodies/org.kivy.android.PythonActivity }
> Error type 3
> Error: Activity class {org.test.kkfoodies/org.kivy.android.PythonActivity} does not exist.
> Application started

Here is my buildozer.spec file

  1. [app]
  2. # (str) Title of your application
  3. title = KK Foodies
  4. # (str) Package name
  5. package.name = kkfoodies
  6. # (str) Package domain (needed for android/ios packaging)
  7. package.domain = org.test
  8. # (str) Source code where the main.py live
  9. source.dir = .
  10. # (list) Source files to include (let empty to include all the files)
  11. source.include_exts = py,png,jpg,kv,atlas
  12. # (list) List of inclusions using pattern matching
  13. #source.include_patterns = assets/*,images/*.png
  14. # (list) Source files to exclude (let empty to not exclude anything)
  15. #source.exclude_exts = spec
  16. # (list) List of directory to exclude (let empty to not exclude anything)
  17. #source.exclude_dirs = tests, bin
  18. # (list) List of exclusions using pattern matching
  19. #source.exclude_patterns = license,images/*/*.jpg
  20. # (str) Application versioning (method 1)
  21. version = 1.0
  22. # (str) Application versioning (method 2)
  23. # version.regex = __version__ = ['"](.*)['"]
  24. # version.filename = %(source.dir)s/main.py
  25. # (list) Application requirements
  26. # comma separated e.g. requirements = sqlite3,kivy
  27. requirements = python3,kivy
  28. # (str) Custom source folders for requirements
  29. # Sets custom source for any requirements with recipes
  30. # requirements.source.kivy = ../../kivy
  31. # (list) Garden requirements
  32. #garden_requirements =
  33. # (str) Presplash of the application
  34. #presplash.filename = %(source.dir)s/data/presplash.png
  35. # (str) Icon of the application
  36. #icon.filename = %(source.dir)s/data/icon.png
  37. # (str) Supported orientation (one of landscape, sensorLandscape, portrait or all)
  38. orientation = portrait
  39. # (list) List of service to declare
  40. #services = NAME:ENTRYPOINT_TO_PY,NAME2:ENTRYPOINT2_TO_PY
  41. #
  42. # OSX Specific
  43. #
  44. #
  45. # author = © Copyright Info
  46. # change the major version of python used by the app
  47. osx.python_version = 3
  48. # Kivy version to use
  49. osx.kivy_version = 1.9.1
  50. #
  51. # Android specific
  52. #
  53. # (bool) Indicate if the application should be fullscreen or not
  54. fullscreen = 0
  55. # (string) Presplash background color (for new android toolchain)
  56. # Supported formats are: #RRGGBB #AARRGGBB or one of the following names:
  57. # red, blue, green, black, white, gray, cyan, magenta, yellow, lightgray,
  58. # darkgray, grey, lightgrey, darkgrey, aqua, fuchsia, lime, maroon, navy,
  59. # olive, purple, silver, teal.
  60. #android.presplash_color = #FFFFFF
  61. # (list) Permissions
  62. #android.permissions = INTERNET
  63. # (int) Target Android API, should be as high as possible.
  64. #android.api = 27
  65. # (int) Minimum API your APK will support.
  66. android.minapi = 21
  67. # (int) Android SDK version to use
  68. #android.sdk = 20
  69. # (str) Android NDK version to use
  70. #android.ndk = 17c
  71. # (int) Android NDK API to use. This is the minimum API your app will support, it should usually match android.minapi.
  72. #android.ndk_api = 21
  73. # (bool) Use --private data storage (True) or --dir public storage (False)
  74. #android.private_storage = True
  75. # (str) Android NDK directory (if empty, it will be automatically downloaded.)
  76. #android.ndk_path =
  77. # (str) Android SDK directory (if empty, it will be automatically downloaded.)
  78. #android.sdk_path =
  79. # (str) ANT directory (if empty, it will be automatically downloaded.)
  80. #android.ant_path =
  81. # (bool) If True, then skip trying to update the Android sdk
  82. # This can be useful to avoid excess Internet downloads or save time
  83. # when an update is due and you just want to test/build your package
  84. # android.skip_update = False
  85. # (bool) If True, then automatically accept SDK license
  86. # agreements. This is intended for automation only. If set to False,
  87. # the default, you will be shown the license when first running
  88. # buildozer.
  89. # android.accept_sdk_license = False
  90. # (str) Android entry point, default is ok for Kivy-based app
  91. #android.entrypoint = org.renpy.android.PythonActivity
  92. # (str) Android app theme, default is ok for Kivy-based app
  93. # android.apptheme = "@android:style/Theme.NoTitleBar"
  94. # (list) Pattern to whitelist for the whole project
  95. #android.whitelist =
  96. # (str) Path to a custom whitelist file
  97. #android.whitelist_src =
  98. # (str) Path to a custom blacklist file
  99. #android.blacklist_src =
  100. # (list) List of Java .jar files to add to the libs so that pyjnius can access
  101. # their classes. Don't add jars that you do not need, since extra jars can slow
  102. # down the build process. Allows wildcards matching, for example:
  103. # OUYA-ODK/libs/*.jar
  104. #android.add_jars = foo.jar,bar.jar,path/to/more/*.jar
  105. # (list) List of Java files to add to the android project (can be java or a
  106. # directory containing the files)
  107. #android.add_src =
  108. # (list) Android AAR archives to add (currently works only with sdl2_gradle
  109. # bootstrap)
  110. #android.add_aars =
  111. # (list) Gradle dependencies to add (currently works only with sdl2_gradle
  112. # bootstrap)
  113. #android.gradle_dependencies =
  114. # (list) add java compile options
  115. # this can for example be necessary when importing certain java libraries using the 'android.gradle_dependencies' option
  116. # see https://developer.android.com/studio/write/java8-support for further information
  117. # android.add_compile_options = "sourceCompatibility = 1.8", "targetCompatibility = 1.8"
  118. # (list) Gradle repositories to add {can be necessary for some android.gradle_dependencies}
  119. # please enclose in double quotes
  120. # e.g. android.gradle_repositories = "maven { url 'https://kotlin.bintray.com/ktor' }"
  121. #android.add_gradle_repositories =
  122. # (list) packaging options to add
  123. # see https://google.github.io/android-gradle- dsl/current/com.android.build.gradle.internal.dsl.PackagingOptions.html
  124. # can be necessary to solve conflicts in gradle_dependencies
  125. # please enclose in double quotes
  126. # e.g. android.add_packaging_options = "exclude 'META- INF/common.kotlin_module'", "exclude 'META-INF/*.kotlin_module'"
  127. #android.add_gradle_repositories =
  128. # (list) Java classes to add as activities to the manifest.
  129. #android.add_activites = com.example.ExampleActivity
  130. # (str) OUYA Console category. Should be one of GAME or APP
  131. # If you leave this blank, OUYA support will not be enabled
  132. #android.ouya.category = GAME
  133. # (str) Filename of OUYA Console icon. It must be a 732x412 png image.
  134. #android.ouya.icon.filename = %(source.dir)s/data/ouya_icon.png
  135. # (str) XML file to include as an intent filters in <activity> tag
  136. #android.manifest.intent_filters =
  137. # (str) launchMode to set for the main activity
  138. #android.manifest.launch_mode = standard
  139. # (list) Android additional libraries to copy into libs/armeabi
  140. #android.add_libs_armeabi = libs/android/*.so
  141. #android.add_libs_armeabi_v7a = libs/android-v7/*.so
  142. #android.add_libs_arm64_v8a = libs/android-v8/*.so
  143. #android.add_libs_x86 = libs/android-x86/*.so
  144. #android.add_libs_mips = libs/android-mips/*.so
  145. # (bool) Indicate whether the screen should stay on
  146. # Don't forget to add the WAKE_LOCK permission if you set this to True
  147. #android.wakelock = False
  148. # (list) Android application meta-data to set (key=value format)
  149. #android.meta_data =
  150. # (list) Android library project to add (will be added in the
  151. # project.properties automatically.)
  152. #android.library_references =
  153. # (list) Android shared libraries which will be added to AndroidManifest.xml using <uses-library> tag
  154. #android.uses_library =
  155. # (str) Android logcat filters to use
  156. #android.logcat_filters = *:S python:D
  157. # (bool) Copy library instead of making a libpymodules.so
  158. #android.copy_libs = 1
  159. # (str) The Android arch to build for, choices: armeabi-v7a, arm64-v8a, x86, x86_64
  160. android.arch = armeabi-v7a
  161. #
  162. # Python for android (p4a) specific
  163. #
  164. # (str) python-for-android fork to use, defaults to upstream (kivy)
  165. #p4a.fork = kivy
  166. # (str) python-for-android branch to use, defaults to master
  167. #p4a.branch = master
  168. # (str) python-for-android git clone directory (if empty, it will be automatically cloned from github)
  169. #p4a.source_dir =
  170. # (str) The directory in which python-for-android should look for your own build recipes (if any)
  171. #p4a.local_recipes =
  172. # (str) Filename to the hook for p4a
  173. #p4a.hook =
  174. # (str) Bootstrap to use for android builds
  175. # p4a.bootstrap = sdl2
  176. # (int) port number to specify an explicit --port= p4a argument (eg for bootstrap flask)
  177. #p4a.port =
  178. #
  179. # iOS specific
  180. #
  181. # (str) Path to a custom kivy-ios folder
  182. #ios.kivy_ios_dir = ../kivy-ios
  183. # Alternately, specify the URL and branch of a git checkout:
  184. ios.kivy_ios_url = https://github.com/kivy/kivy-ios
  185. ios.kivy_ios_branch = master
  186. # Another platform dependency: ios-deploy
  187. # Uncomment to use a custom checkout
  188. #ios.ios_deploy_dir = ../ios_deploy
  189. # Or specify URL and branch
  190. ios.ios_deploy_url = https://github.com/phonegap/ios-deploy
  191. ios.ios_deploy_branch = 1.7.0
  192. # (str) Name of the certificate to use for signing the debug version
  193. # Get a list of available identities: buildozer ios list_identities
  194. #ios.codesign.debug = "iPhone Developer: <lastname> <firstname> (<hexstring>)"
  195. # (str) Name of the certificate to use for signing the release version
  196. #ios.codesign.release = %(ios.codesign.debug)s
  197. [buildozer]
  198. # (int) Log level (0 = error only, 1 = info, 2 = debug (with command output))
  199. log_level = 2
  200. # (int) Display warning if buildozer is run as root (0 = False, 1 = True)
  201. warn_on_root = 1
  202. # (str) Path to build artifact storage, absolute or relative to spec file
  203. # build_dir = ./.buildozer
  204. # (str) Path to build output (i.e. .apk, .ipa) storage
  205. # bin_dir = ./bin
  206. # -----------------------------------------------------------------------------
  207. # List as sections
  208. #
  209. # You can define all the "list" as [section:key].
  210. # Each line will be considered as a option to the list.
  211. # Let's take [app] / source.exclude_patterns.
  212. # Instead of doing:
  213. #
  214. #[app]
  215. #source.exclude_patterns = license,data/audio/*.wav,data/images/original/*
  216. #
  217. # This can be translated into:
  218. #
  219. #[app:source.exclude_patterns]
  220. #license
  221. #data/audio/*.wav
  222. #data/images/original/*
  223. #
  224. # -----------------------------------------------------------------------------
  225. # Profiles
  226. #
  227. # You can extend section / key with a profile
  228. # For example, you want to deploy a demo version of your application without
  229. # HD content. You could first change the title to add "(demo)" in the name
  230. # and extend the excluded directories to remove the HD content.
  231. #
  232. #[app@demo]
  233. #title = My Application (demo)
  234. #
  235. #[app:source.exclude_patterns@demo]
  236. #images/hd/*
  237. #
  238. # Then, invoke the command line with the "demo" profile:
  239. #
  240. #buildozer --profile demo android debug

The python file is given below.

  1. from kivy.app import App
  2. from kivy.properties import ObjectProperty
  3. from kivy.uix.boxlayout import BoxLayout
  4. from kivy.uix.relativelayout import RelativeLayout
  5. from kivy.uix.scrollview import ScrollView
  6. from kivy.uix.label import Label
  7. from kivy.uix.button import Button
  8. from kivy.uix.togglebutton import ToggleButton
  9. from kivy.uix.checkbox import CheckBox
  10. from kivy.uix.spinner import Spinner
  11. from kivy.properties import NumericProperty #, ListProperty
  12. from kivy.uix.textinput import TextInput
  13. from kivy.uix.popup import Popup
  14. # from kivy.uix.bubble import Bubble
  15. from kivy.uix.image import Image
  16. from kivy.lang import Builder
  17. import MySQLdb
  18. import hashlib, binascii, os
  19. from kivy.uix.screenmanager import ScreenManager, Screen
  20. # from datetime import date, timedelta
  21. from kivy.uix.popup import Popup
  22. from datepicker import DatePicker # , CalendarWidget
  23. import base64
  24. from functools import partial
  25. import textwrap
  26. # import numpy as np
  27. # import cv2
  28. # import io
  29. # import PIL.Image
  30. #_imaging = PIL.Image.core
  31. # from PIL import Image
  32. # from PIL.Image import core as _imaging
  33. # import Image
  34. # import sys
  35. # import cStringIO
  36. # import timepicker
  37. # from kivy.garden.circulardatetimepicker import CircularTimePicker
  38. from kivy.core.window import Window
  39. # Window.clearcolor = (204/255, 1, 244/255, 0)
  40. class ScreenManagement(ScreenManager):
  41. pass
  42. myname = ''
  43. selldate = ''
  44. roomno = ''
  45. try:
  46. dbconnect = MySQLdb.connect("IP", "username", "password",
  47. "dbname")
  48. except (MySQLdb.Error) as e: # , MySQLdb.Warning
  49. print("Can't connect to database", e)
  50. exit()
  51. # return 0
  52. # If Connection Is Successful
  53. # print("Connected")
  54. crsr = dbconnect.cursor()
  55. class ListHeader(Button):
  56. def __init__(self, **kwargs):
  57. super().__init__(**kwargs)
  58. # bcolor = ListProperty([1, 1, 1, 1])
  59. class ListCell(Label):
  60. def __init__(self, **kwargs):
  61. super().__init__(**kwargs)
  62. # bcolor = ListProperty([1, 1, 1, 1])
  63. class DbCon:
  64. def __init__(self, **kwargs):
  65. super().__init__(**kwargs)
  66. def get_row(self, uname):
  67. query = "SELECT username, passwordh, emp_no, full_name, room_no, authorisation_flag FROM residents WHERE username = '%s" % uname + "'"
  68. # query = "SELECT userid, pass, mob, fname, lname, mailid FROM login_data WHERE userid = '%s" % uname + "'"
  69. print(query)
  70. crsr.execute(query)
  71. return crsr.fetchone()
  72. def add_row(self, username, password, empnum, fullname, roomnum):
  73. hashedpwd = self.hash_password(password)
  74. print(hashedpwd)
  75. sqlquery = "INSERT INTO residents (username, passwordh, emp_no, full_name, room_no) VALUES (%s, %s, %s, %s, %s)"
  76. insert_values = (username, hashedpwd, empnum, fullname, roomnum)
  77. crsr.execute(sqlquery, insert_values)
  78. dbconnect.commit()
  79. print(crsr.rowcount, " record inserted.")
  80. def hash_password(self, password):
  81. """Hash a password for storing."""
  82. salt = hashlib.sha256(os.urandom(60)).hexdigest().encode('ascii')
  83. pwdhash = hashlib.pbkdf2_hmac('sha512', password.encode('utf-8'),
  84. salt, 10000)
  85. pwdhash = binascii.hexlify(pwdhash)
  86. return (salt + pwdhash).decode('ascii')
  87. class LoginWindow(Screen):
  88. def __init__(self, **kwargs):
  89. super().__init__(**kwargs)
  90. self.db = DbCon()
  91. def validate_user(self):
  92. user = self.ids.username_field
  93. pwd = self.ids.pwd_field
  94. info = self.ids.info
  95. global myname, roomno
  96. uname = user.text
  97. passw = pwd.text
  98. if uname == '' or passw == '':
  99. info.text = '[color=#FF0000]username and/ or password required[/color]'
  100. else:
  101. row = self.db.get_row(uname)
  102. if row == '':
  103. info.text = '[color=#FF0000]Invalid Username and/or Password[/color]'
  104. else:
  105. stored_passwd = row[1]
  106. myname = row[3]
  107. roomno = row[4]
  108. print(stored_passwd)
  109. print(passw)
  110. if self.verify_password(stored_passwd, passw):
  111. # if stored_passwd == passw:
  112. if row[5] == 1:
  113. info.text = '[color=#00FF00]Logged In successfully!!![/color]'
  114. self.parent.current = 'menu'
  115. else:
  116. info.text = '[color=#FF0000]Sorry, you are not authorised. Please collect authorisation details from administrator.[/color]'
  117. else:
  118. info.text = '[color=#FF0000]Incorrect Password[/color]'
  119. def verify_password(self, stored_password, provided_password):
  120. """Verify a stored password against one provided by user"""
  121. salt = stored_password[:64]
  122. stored_password = stored_password[64:]
  123. pwdhash = hashlib.pbkdf2_hmac('sha512',
  124. provided_password.encode('utf-8'),
  125. salt.encode('ascii'),
  126. 10000)
  127. pwdhash = binascii.hexlify(pwdhash).decode('ascii')
  128. print(pwdhash)
  129. return pwdhash == stored_password
  130. class RegisterWindow(Screen):
  131. def __init__(self, **kwargs):
  132. super().__init__(**kwargs)
  133. self.db2 = DbCon()
  134. def register_user(self):
  135. user = self.ids.username_field
  136. pwd = self.ids.pwd_field
  137. rpt_pwd = self.ids.pwd_field_rpt
  138. fname = self.ids.full_name
  139. empnum = self.ids.emp_no
  140. roomnum = self.ids.room_no
  141. info = self.ids.info
  142. uname = user.text
  143. passw = pwd.text
  144. rpassw = rpt_pwd.text
  145. name = fname.text
  146. enum = empnum.text
  147. rnum = roomnum.text
  148. unameokflag = False
  149. passwokflag = False
  150. nameokflag = False
  151. enumokflag = False
  152. rnumokflag = False
  153. info.text = ''
  154. if uname == '':
  155. info.text += '[color=#FF0000]username required[/color]'
  156. else:
  157. unameokflag = True
  158. if passw == '':
  159. info.text += '\n[color=#FF0000]password required[/color]'
  160. if rpassw == '':
  161. info.text += '\n[color=#FF0000]repeat password required[/color]'
  162. if name == '':
  163. info.text += '\n[color=#FF0000]full name required[/color]'
  164. else:
  165. nameokflag = True
  166. if enum == '':
  167. info.text += '\n[color=#FF0000]mobile required[/color]'
  168. elif len(enum) != 10 or enum.isdigit() != True:
  169. info.text += '\n[color=#FF0000]not a valid mobile number[/color]'
  170. else:
  171. enumokflag = True
  172. if rnum == '':
  173. info.text += '\n[color=#FF0000]room number required[/color]'
  174. else:
  175. rnumokflag = True
  176. if passw != '' and rpassw != '' and passw != rpassw:
  177. info.text += '\n[color=#FF0000]passwords do not match[/color]'
  178. else:
  179. passwokflag = True
  180. if unameokflag and passwokflag and nameokflag and enumokflag and rnumokflag:
  181. self.db2.add_row(uname, passw, enum, name, rnum)
  182. info.text += '\n[color=#FF0000]resident details successfully inserted[/color]'
  183. class FoodiesApp(App):
  184. def build(self):
  185. return ScreenManagement()
  186. if __name__=="__main__":
  187. sa = FoodiesApp()
  188. sa.run()

Kindly help me solve the issue.

答案1

得分: 3

让我回答自己的问题。问题已解决。错误“错误类型3 错误:Activity类{org.test.kkfoodies/org.kivy.android.PythonActivity}不存在。”导致极度困惑。这个错误是因为该应用部署在一个安卓手机上,而该手机的最低API要求没有满足(在buildozer规范文件中android.minapi = 21选项)。将该选项值更改为小于21也没有帮助,因为buildozer版本不支持在旧的API上部署。

然后在满足最低API要求的安卓手机上测试了该应用。但是Python库mysqldb引发了问题。将mysqldb选项添加到requirements属性中并尝试了名为mysqldb的配方。但是,这两次尝试都失败了。


最终,源代码文件main.py被修改 - 使用了mysql.connector库来代替MySQLdb。还在buildozer.spec文件的requirements属性中添加了mysql_connector选项。这解决了问题。该应用现在在安卓手机上(Android版本为Lollipop及更高版本)平稳运行。我感谢你们每一个人提供的帮助。

英文:

Let me answer my own question. The problem is resolved. The error "Error type 3 Error: Activity class {org.test.kkfoodies/org.kivy.android.PythonActivity} does not exist." was causing utter confusion. This error was coming because the app was deployed on an android mobile phone where the minimum api requirement is not satisfied. (android.minapi = 21 option in buildozer spec file). Changing the option value to less than 21 also did not help as the buildozer version was not supporting deployment on older APIs.
The app was then tested on android phone which met the minimum api requirement. But the python library mysqldb was causing issues. mysqldb option was added in the requirements attribute and the recipe named mysqldb was tried. But, both the attempts failed.


Finally, the source code file main.py was modified -- mysql.connector library was used in place of MySQLdb. Also mysql_connector option was added in the requirements attribute of buildozer.spec file. That did the trick. The app is working smoothly on android phones now (Android version Lollipop and later). I thank every one of you for the help extended.

huangapple
  • 本文由 发表于 2020年4月4日 02:24:07
  • 转载请务必保留本文链接:https://go.coder-hub.com/61018170.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定