I try to make a simple app that open a web page inside Kivy after clicking a button placed on a "Screen One".
I used this topic (Python - Showing a web browser/iframe right into the app) as reference but I didn't understand how to use the code provided by Michael...
So I tried this... and when I launch the apk (build with Buildozer) it didn't work :')
import kivy
kivy.require('1.9.2')
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen
# MICHAEL'S CODE
from kivy.utils import platform
from kivy.uix.widget import Widget
from kivy.clock import Clock
from jnius import autoclass
from android.runnable import run_on_ui_thread
WebView = autoclass('android.webkit.WebView')
WebViewClient = autoclass('android.webkit.WebViewClient')
activity = autoclass('org.renpy.android.PythonActivity').mActivity
class Wv(Widget):
def __init__(self, **kwargs):
super(Wv, self).__init__(**kwargs)
Clock.schedule_once(self.create_webview, 0)
#run_on_ui_thread
def create_webview(self, *args):
webview = WebView(activity)
webview.getSettings().setJavaScriptEnabled(True)
wvc = WebViewClient();
webview.setWebViewClient(wvc);
activity.setContentView(webview)
webview.loadUrl('http://www.google.com/')
# END OF MICHAEL'S CODE
Builder.load_string('''
<ScreenOne>:
BoxLayout:
Label:
text: "SCREEN 1"
Button:
text: "GO GO GO TO GOOGLE !"
on_press: root.open_browser()
<ScreenTwo>:
BoxLayout:
Label:
text: "SCREEN 2"
Button:
text: "GO GO GO TO SCREEN 1"
on_press:
root.manager.transition.direction = "right"
root.manager.transition.duration = 1
root.manager.current = "screen_one"
''')
class ScreenOne(Screen):
def open_browser(self):
return Wv()
class ScreenTwo(Screen):
pass
screen_manager = ScreenManager()
screen_manager.add_widget(ScreenOne(name="screen_one"))
screen_manager.add_widget(ScreenTwo(name="screen_two"))
class BrowserApp(App):
def build(self):
return screen_manager
app = BrowserApp()
app.run()
The app don't crash but just close when I start it.
What I'm doing wrong ? I'm sure that I don't use it the right way...
Log from adb logcat:
06-13 12:54:47.559 7429 7510 I python : ImportError: No module named android
06-13 12:54:47.579 7429 7510 I python : Python for android ended.
From the log you posted in the comments I extracted the two important lines:
06-13 12:54:47.559 7429 7510 I python : ImportError: No module named android
06-13 12:54:47.579 7429 7510 I python : Python for android ended.
This basically means that the copied code:
from android.runnable import run_on_ui_thread
won't work because it doesn't detect the android module. The module has a separate recipe, therefore you will need to add it to the requirements, so that it compiles the Cython code and adds it to your app, otherwise the import will always fail.
Basically you always want to search for 3-4 keywords when looking into such a messy logcat → "python", "Traceback", "Python for android", "kivy". There's a filter in buildozer for that if you use it:
android.logcat_filters = *:S python:D
Related
I have done successfully to convert a very simple python scripts into android apps using colab buildozer.
I uses only kivymd.app
However when I added kivymd.uix.pickers, it crashes when I run the app in my android phone.
Please tell me what was wrong and simple solution.
I have editted the buildozer.spec line 40 to: requirements = python3,kivy,kivymd
Below are the py and kv file.
#main.py
from kivymd.app import MDApp
from kivymd.uix.pickers import MDDatePicker
class MainApp(MDApp):
def build(self):
self.theme_cls.primary_palette = "DeepPurple"
def show_date_picker(self):
date_dialog = MDDatePicker()
date_dialog.open()
if __name__ == '__main__':
app = MainApp()
app.run()
MDFloatLayout:
MDLabel:
text: "My Tasks"
pos_hint: {'x': .5,'y': .45}
MDRectangleFlatButton:
text: 'Date Picker'
pos_hint: {'x': .5, 'y':.5}
on_release: app.show_date_picker()
I was wondering if there is any way to keep widgets that are added later during the application use. Whenever the app restarts, the build() function is called, and the widgets that have been added during the app usage disappear since they were not added in build() function.
I want to keep these widgets in the restart in the same way the app keeps them in Pause mode.
Thank you!
Here is a simple example of using an ini file with your Kivy App:
import os
import ast
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.label import Label
kv = '''
BoxLayout:
orientation: 'vertical'
BoxLayout:
orientation: 'horizontal'
size_hint_y: 0.15
Button:
text: 'Add Widget'
on_release: app.do_add()
Button:
text: 'Some Button'
Button:
text: 'Another Button'
BoxLayout:
size_hint_y: 0.85
orientation: 'vertical'
id: box
'''
class TestApp(App):
def build(self):
self.count = 0 # counter used in Label text
return Builder.load_string(kv)
def build_config(self, config):
# Make sure that the config has at least default entries that we need
config.setdefaults('app', {
'labels': '[]',
})
def get_application_config(self):
# This defines the path and name where the ini file is located
return str(os.path.join(os.path.expanduser('~'), 'TestApp.ini'))
def on_start(self):
# the ini file is read automatically, here we initiate doing something with it
self.load_my_config()
def on_stop(self):
# save the config when the app exits
self.save_config()
def do_add(self):
self.count += 1
self.root.ids.box.add_widget(Label(text='Label ' + str(self.count)))
def save_config(self):
# this writes the data we want to save to the config
labels = []
for wid in self.root.ids.box.children:
labels.append(wid.text)
# set the data in the config
self.config.set('app', 'labels', str(labels))
# write the config file
self.config.write()
def load_my_config(self):
# extract our saved data from the config (it has already been read)
labels_str = self.config.get('app', 'labels')
# us the extracted data to build the Labels
labels = ast.literal_eval(labels_str)
labels.reverse()
self.count = len(labels)
for lab in labels:
self.root.ids.box.add_widget(Label(text=lab))
if __name__ == '__main__':
TestApp().run()
I'm trying to study Kivy, so I've done a simple gui that work on windows but when I run it on Android with Kivy Launcher I'm getting this error trought ADB LOGCAT :
This is a simple kv code :
#:kivy 1.0.9
<ROT>:
FloatLayout:
AnchorLayout:
anchor_x:"center"
anchor_y: "top"
Button:
size_hint : 1,1
text : "prova"
on_press: root.press()
and this is the main.py :
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
class ROT(Widget):
def press(self):
print "ciao"
pass
class PongApp(App):
def build(self):
self.root = Builder.load_file('questionario.kv')
return ROT()
if __name__ == '__main__':
PongApp().run()
I can't understand why it doesn't want to work
This is an app written in python 2.7 using kivy and numpy modules. I have installed buildozer by following steps in this link : https://github.com/kivy/buildozer , i did not do sudo pip install https://github.com/kivy/buildozer/archive/master.zip. After deploying the app on android buildozer android deploy run logcat i saw some errors on the log :
10-10 17:44:49.497 19176 19207 I python : [ERROR ] [Image ] Error reading file .\logo_example1.png
10-10 17:44:49.498 19176 19207 I python : [WARNING] [Base ] Unknown <android> provider
10-10 17:44:49.498 19176 19207 I python : [INFO ] [Base ] Start application main loop
10-10 17:44:49.503 19176 19207 I python : [INFO ] [GL ] NPOT texture support is available
10-10 17:44:49.504 19176 19207 I python : 0
10-10 17:44:49.504 19176 19207 I python : coloring
10-10 17:44:49.505 19176 19207 I python : [ERROR ] [Base ] Failed to import "android" module. Could not remove android presplash.
Problem : The Image widget does not show, and the touch for the button does not seem to receive any event/response. May I have feedbacks on this, thanks.
Current partially solved : The Image widget now shows, I change the source address from .\\logo_example1.png to logo_example1.png.
Existing problem : the Button widget is still unresponsive to touch on android, but works fine on Windows.
Code to test Start and Back buttons :
This is the main.kv :
#: import Main main
<CtmButton#Button>:
font_size:30
size:100, 50
<BackButton#Button>:
font_size:30
size:100, 50
text: "Back"
pos: Main.Wsize[0]+100, Main.Wsize[1]+100
<mainWidget>:
id: main_widget
<homeWidget>:
id: home_widget
padding : 200
Image:
id:logo
source: 'logo_example1.png'
center: 300, 450
CtmButton:
id: start_button
text: "Start"
center:300, 200
on_release: home_widget.startbutton_function()
## I also have tried replacing this with on_touch_down
## to see whether it will solve the problem
<puzzleWidget>:
id: puzzle_widget
BackButton:
id: back_button_1
center: 100, 37.5
on_release: puzzle_widget.backbutton_function()
This is the main.py:
import kivy
from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.label import Label
from kivy.core.window import Window
from kivy.uix.image import Image
from kivy.core.image import ImageData
from kivy.clock import Clock
from kivy.graphics import Rectangle
import time
import math
import itertools
import numpy
Window.clearcolor = (0.2, 0.25, 0.2, 0.5); col_dx = 0.005; y = list(Window.clearcolor); xstart = 0;
Window.size = (600, 700); Wsize = Window.size;
class mainWidget(Widget):
def __init__(self):
Widget.__init__(self);
home = homeWidget(); self.add_widget(home);
class homeWidget(Widget):
def __init__(self):
Widget.__init__(self);
self.bg_animate();
def printingsomething(self, dt):
print(dt);
def bg_animate(self):
global bg_anim
self.bg_anim = Clock.schedule_interval(self.printingsomething,1/40);
self.bg_anim();
def startbutton_function(self):
print('start pressed');
self.bg_anim.cancel();
mainw.clear_widgets();
mainw.add_widget(puzzleWidget());
class puzzleWidget(Widget):
def __init__(self):
Widget.__init__(self);
self.Bar1 = Image(size = [600, 75], color = list(Window.clearcolor)); self.Bar1.color[-1] = 0.8; self.Bar1.pos = [0, 700 - self.Bar1.size[1]];
self.Bar2 = Image(size = [600, 75], color = list(Window.clearcolor)); self.Bar2.color[-1] = 0.8; self.Bar2.pos = [0, 0];
#### ADD WIDGET(S):
self.add_widget(self.Bar1); self.add_widget(self.Bar2);
self.remove_widget(self.ids.back_button_1); self.add_widget(self.ids.back_button_1);
def backbutton_function(self):
print('back pressed');
self.clear_widgets();
mainw.clear_widgets();
mainw.add_widget(homeWidget());
################## main window for the app #########################
class mainApp(App):
def build(self):
global mainw
mainw = mainWidget();
return mainw
####################################################################
mainApp = mainApp()
mainApp.run();
Failed to import "android" module.
This msg has nothing to do with image. It's won't affect your project if you don't use android module explicitly. All you need to do to avoid this line in logs is to add android to requirements inside buildozer.spec.
Error reading file .\logo_example1.png
This error indicates that image can't be found. I don't know what's problem with .\\logo_example1.png, but it's better just to use absolute path's and forget about problems.
import os
root_dir = os.path.dirname(os.path.abspath(__file__))
img_rel = 'logo_example1.png'
img_abs = os.path.join(root_dir, img_rel)
print(img_abs)
Upd:
Problem with pressing is related to this line - Window.size = (600, 700). Remove it and everything will work.
Looks like changing Window.size somehow breaks kivy touch point detection. If you want to change window size on Windows, use Config or wrap Window.size changing with platform check.
I am using example from Kivy documentation, only line i added is import numpy. After packaging it for android i cant run on my phone it never starts. However on removing this line and then building works fine.
python file: main.py
__version__="1.0.0"
import colorsys
import numpy as np
import kivy
kivy.require('1.0.7')
from kivy.animation import Animation
from kivy.app import App
from kivy.uix.button import Button
class TestApp(App):
def animate(self, instance):
animation = Animation(pos=(100, 100), t='out_bounce')
animation += Animation(pos=(200, 100), t='out_bounce')
animation &= Animation(size=(500, 500))
animation += Animation(size=(100, 50))
animation.start(instance)
def build(self):
button = Button(size_hint=(None, None), text='plop',
on_press=self.animate)
return button
if __name__ == '__main__':
TestApp().run()
In buildozer.spec file under requirement i have included kivy, numpy.
Check the log to see what's wrong.