Canonical Voices

What Ubuntu Touch Development in CSDN (Chinese) talks about

UbuntuTouch

我们知道对于python项目来说,我们只需要在我们的snapcraft.yaml中指定plugin为python它即可为python项目下载在snapcraft中指定的python的版本。但是对于有一些项目来说,我们的开发者可能需要一个特定的python的版本,那么我们怎么来实现这个功能呢?在今天的教程中,我们来介绍在snapcraft 2.27中所增添的一个新的功能。


我们首先来看一下我做的一个项目:

https://github.com/liu-xiao-guo/python-plugin

snapcraft.yaml

name: python36
version: '0.1' 
summary: This is a simple example not using python plugin
description: |
  This is a python3 example

grade: stable 
confinement: strict

apps:
  python36:
    command: helloworld_in_python
  python-version:
    command: python3 --version

parts:
  my-python-app:
    source: https://github.com/liu-xiao-guo/python-helloworld.git
    plugin: python
    after: [python]
  python:
    source: https://www.python.org/ftp/python/3.6.0/Python-3.6.0.tar.xz
    plugin: autotools
    configflags: [--prefix=/usr]
    build-packages: [libssl-dev]
    prime:
      - -usr/include

在这里,针对我们的python项目,它指定了在我们项目python part中所定义的python。这个python的版本是直接从网上直接进行下载的。

我们可以直接打包我们的应用,并并运行我们的应用:

$ python36
Hello, world

显然我们的python是可以正常工作的。我们可以通过命令python36.python-version命令来检查我们的python的版本:

$ python36.python-version 
Python 3.6.0

它显示了,我们目前正在运行的python的版本3.6。它就是我们在snapcraft中所下载的版本。
作者:UbuntuTouch 发表于2017/2/20 9:23:30 原文链接
阅读:127 评论:0 查看评论

Read more
UbuntuTouch

在最新的snapd 2.20中,它开始支持一个叫做classic模式的snap 应用开发.这种classic可以使得我们的应用开发者能够快速地开发我们所需要的应用,这是因为我们不必要对我们的现有的应用做太多的改变.在classic模式下的应用,它可以看见host系统的所有的位于"/"下的文件,就像我们目前正常的应用一样.但是在安装我们的应用后,它的所有文件将位于/snap/foo/current下.它的执行文件将位于/snap/bin目录下,就像我们目前的所有其它的snap应用一样.

当我们安装我们的classic模式下的snap应用时,我们需要使用--classic选项.在上传我们的应用到Ubuntu Core商店时,也需要人工检查.它可以看见位于/snap/core/current下的所有的文件,同时也可以对host里的任何位置的文件进行操作.这样做的目的是为了能够使得开发者快速地发布自己的以snap包为格式的应用,并在以后的开发中逐渐运用Ubuntu Core的confinement以得到完善.在目前看来,classic模式下的应用在可以遇见的将来不能够安装到all-snap系统中,比如Ubuntu Core 16.

对于classic模式的应用来说,它的"/"目录对应于host系统的"/".更多的信息可以参阅地址:http://snapcraft.io/docs/reference/confinement


安装

在开发之前,我们在desktop上安装core而不是ubuntu-core.我们可以用snap list命令来查看:

liuxg@liuxg:~$ snap list
Name          Version  Rev  Developer  Notes
core          16.04.1  714  canonical  -
firefox-snap  0.1      x1              classic
hello         1.0      x1              devmode
hello-world   6.3      27   canonical  -

如果你的系统里是安装的ubuntu-core的话,建议大家使用devtool中的reset-state来使得我们的系统恢复到最初的状态(没有任何安装的snap).在以后的snapd发布中,我们将不再有ubuntu-core这个snap了.我们也可以适用如下的方法来删除ubuntu-core snap并安装上core snap:

$ sudo apt purge -y snapd
$ sudo apt install snapd
$ sudo snap install core

另外对于有的开发者来说从stable channel得不到最新的snap 2.20,我们可以在我们的Ubuntu Destkop中,打开"System Settings"/"Software & Updates"/"Developer Options":


我们可以打开上面所示的开关,就可以得到最新的所有关于我们Ubuntu桌面系统的发布的软件.snap 2.20版本目前就在这个xenial-proposed之中.

在今天的教程中,我们来做一个例程来进行将讲解:

https://github.com/liu-xiao-guo/helloworld-classic

在上面的例程中,它的snapcraft.yaml的文件如下:

snapcraft.yaml

name: hello
version: "1.0"
summary: The 'hello-world' of snaps
description: |
    This is a simple snap example that includes a few interesting binaries
    to demonstrate snaps and their confinement.
    * hello-world.env  - dump the env of commands run inside app sandbox
    * hello-world.evil - show how snappy sandboxes binaries
    * hello-world.sh   - enter interactive shell that runs in app sandbox
    * hello-world      - simply output text
grade: stable
confinement: classic
type: app  #it can be gadget or framework

apps:
 env:
   command: bin/env
 evil:
   command: bin/evil
 sh:
   command: bin/sh
 hello-world:
   command: bin/echo
 createfile:
   command: bin/createfile
 createfiletohome:
   command: bin/createfiletohome
 listhome:
   command: bin/listhome
 showroot:
   command: bin/showroot

parts:
 hello:
  plugin: dump
  source: .    

从上面的例程中,我们可以看出来,我们在confinement的位置定义为:

confinement: classic

这定义了我们的这个snap应用是一个classic的应用.我们安装时也必须使用--classic的选项来进行安装.细心的开发者会发现,在我们的应用中,我们没有定义任何的plug,也就是我们没有使用任何的interface.大家可以和我们的另外一个项目https://github.com/liu-xiao-guo/helloworld-demo进行比较一下.

就像我们之前所说的,我们只希望能尽快把我们的应用以snap形式发布,在classic模式下,我们暂时不考虑安全的问题.

我们可以打包我们的应用,并以如下的命令来进行安装:

$ sudo snap install hello_1.0_amd64.snap --classic --dangerous

我们的脚本showroot内容如下:

#!/bin/bash

cd /
echo "list all of the content in the root:"
ls

echo "show the home content:"
cd home
ls

当我们运行我们的应用showroot时,我们可以看到:

liuxg@liuxg:~/snappy/desktop/helloworld-classic$ hello.showroot 
list all of the content in the root:
bin    core  home	     lib	 media	proc  sbin  sys  var
boot   dev   initrd.img      lib64	 mnt	root  snap  tmp  vmlinuz
cdrom  etc   initrd.img.old  lost+found  opt	run   srv   usr  vmlinuz.old
show the home content:
liuxg  root.ini
liuxg@liuxg:~/snappy/desktop/helloworld-classic$ ls /
bin    core  home            lib         media  proc  sbin  sys  var
boot   dev   initrd.img      lib64       mnt    root  snap  tmp  vmlinuz
cdrom  etc   initrd.img.old  lost+found  opt    run   srv   usr  vmlinuz.old

显然,它可以看到我们整个host系统的文件目录.这个应用时间上可以对它所看到的文件及目录进行操作.
当然,我们也可以运行evil脚本:

#!/bin/sh

set -e
echo "Hello Evil World!"

echo "This example demonstrates the app confinement"
echo "You should see a permission denied error next"

echo "Haha" > /var/tmp/myevil.txt

echo "If you see this line the confinement is not working correctly, please file a bug"
运行结果如下:

liuxg@liuxg:~/snappy/desktop/helloworld-classic$ hello.evil
Hello Evil World!
This example demonstrates the app confinement
You should see a permission denied error next
If you see this line the confinement is not working correctly, please file a bug

显然在我们没有使用interface的情况下,我们可以想其它的任何目录进行操作,并写入我们想要的数据.confinement在classic模式下不起任何的作用.对于我们开发者来说,我们只需要快速地把我的应用打包为snap即可.

最后,作为一个速成的例子,我们通过classic模式来快速地把Firefox打包为一个snap:

Firefox snapcraft.yaml

name: firefox-snap
version: '0.1'
summary: "A Firefox snap"
description: "Firefox in a classic confined snap"

grade: devel
confinement: classic

apps:
  firefox-snap:
    command: firefox
    aliases: [firefox]

parts:
  firefox:
    plugin: dump
    source: https://download.mozilla.org/?product=firefox-50.1.0-SSL&os=linux64&lang=en-US
    source-type: tar

在这里,我们直接下载我们需要的版本,并进行打包.安装并运行我们的Firefox应用:



整个项目的源码在地址:https://github.com/liu-xiao-guo/firefox-snap





作者:UbuntuTouch 发表于2017/1/6 13:48:04 原文链接
阅读:386 评论:2 查看评论

Read more
UbuntuTouch

我们知道在一个snap包里,我们可以定义任何数量的app.针对desktop应用来说,那么我们如何使得我们的每个应用都有自己的icon及desktop文件呢?在今天的文章中,我们将介绍如何实现这个.特别注意的是,这个新的feature只有在snapcraft 2.25+版本中才可以有.


首先,我们来看一下我已经做好的一个项目:

https://github.com/liu-xiao-guo/helloworld-desktop

整个应用的文件架构如下:

liuxg@liuxg:~/snappy/desktop/helloworld-desktop$ tree -L 3
.
├── bin
│   ├── createfile
│   ├── createfiletohome
│   ├── echo
│   ├── env
│   ├── evil
│   ├── sh
│   └── writetocommon
├── echo.desktop
├── README.md
├── setup
│   └── gui
│       ├── echo.png
│       ├── helloworld.desktop
│       └── helloworld.png
└── snapcraft.yaml

从上面我们可以看出来,我们已经有一个叫做setup/gui的目录.它里面包含了一个叫做helloworld.desktop的文件:

helloworld.desktop

[Desktop Entry]
Type=Application
Name=Hello
GenericName=Hello world
Comment=A hello world Ubuntu Desktop
Keywords=hello;world;
Exec=hello-xiaoguo.env
Icon=${SNAP}/meta/gui/helloworld.png
Terminal=true
X-Ubuntu-Touch=false
X-Ubuntu-Default-Department-ID=accessories
X-Ubuntu-Splash-Color=#F5F5F5
StartupNotify=true

在这里它指定了这个应用的icon及执行的脚本hello-xiaoguo.env.

我们再来看看我们的snapcraft.yaml文件:

snapcraft.yaml

name: hello-xiaoguo
version: "1.0"
summary: The 'hello-world' of snaps
description: |
    This is a simple snap example that includes a few interesting binaries
    to demonstrate snaps and their confinement.
    * hello-world.env  - dump the env of commands run inside app sandbox
    * hello-world.evil - show how snappy sandboxes binaries
    * hello-world.sh   - enter interactive shell that runs in app sandbox
    * hello-world      - simply output text
grade: stable
confinement: strict
type: app  #it can be gadget or framework

apps:
 env:
   command: bin/env
 evil:
   command: bin/evil
 sh:
   command: bin/sh
 hello-world:
   command: bin/echo
   desktop: usr/share/applications/echo.desktop
 createfile:
   command: bin/createfile
 createfiletohome:
   command: bin/createfiletohome
 writetocommon:
   command: bin/writetocommon

plugs:
    home:
        interface: home

parts:
 hello:
  plugin: dump
  source: .
  organize:
    echo.desktop: usr/share/applications/echo.desktop

在这个文件中,我们也定义了其它的应用,比如hello-world.那么我们如何为它也定义自己的desktop文件呢?答案是:

 hello-world:
   command: bin/echo
   desktop: usr/share/applications/echo.desktop

我们可以在它的command下面指定一个属于自己的desktop文件.在这里我们的echo.desktop文件如下:

echo.desktop

[Desktop Entry]
Type=Application
Name=Echo
GenericName=Hello world
Comment=A hello world Ubuntu Desktop
Keywords=hello;world;
Exec=hello-xiaoguo.hello-world
Icon=${SNAP}/meta/gui/echo.png
Terminal=true
X-Ubuntu-Touch=false
X-Ubuntu-Default-Department-ID=accessories
X-Ubuntu-Splash-Color=#F5F5F5
StartupNotify=true

在这里它指定了自己的执行文件及一个属于自己的icon.我们打包我们的应用,并安装.在Ubuntu Desktop的dash中,我们可以看到:



运行"Hello World"应用显示:



运行我们的"echo"应用:








作者:UbuntuTouch 发表于2017/1/23 10:43:39 原文链接
阅读:258 评论:0 查看评论

Read more
UbuntuTouch

在很多的时候,我们想把一个website变为一个snap应用,从而我们可以直接从商店里进行下载它,并直接使用.我们不需要在浏览器中输入这个网站的地址.也有很多的时候,我们的游戏就在一个网站上,比如http://hexgl.bkcore.com/play/,我们可以直接把该网址打包进我们的snap应用,从而使得它直接可以从商店下载并运行.在今天的教程中,我们来展示如何把网址的url打包到我们的应用中.

为了说明问题方便,我们使用www.sina.com.cn来进行展示:

snapcraft.yaml


name: sina-webapp
version: '1.0'
summary: Sina webapp
description: |
  Webapp version of the Sina web application.

grade: stable
confinement: strict

apps:
  sina-webapp:
    command: webapp-launcher --enable-back-forward --webappUrlPatterns=http?://www.sina.com/* http://www.sina.com/ %u
    plugs:
      - browser-sandbox
      - camera
      - network
      - network-bind
      - opengl
      - pulseaudio
      - screen-inhibit-control
      - unity7
      - network-control
      - mount-observe

plugs:
  browser-sandbox:
    interface: browser-support
    allow-sandbox: false
  platform:
    interface: content
    content: ubuntu-app-platform1
    target: ubuntu-app-platform
    default-provider: ubuntu-app-platform

parts:
  webapp-container:
    after: [desktop-ubuntu-app-platform,webapp-helper]
    stage-packages:
      - fonts-wqy-zenhei
      - fcitx-frontend-qt5
    plugin: nil

在这里,我们使用里desktop-ubuntu-app-platform cloud part.注意在这里,我们也加入了对中文字体及输入法的支持:

      - fonts-wqy-zenhei
      - fcitx-frontend-qt5

我们可以参考我先前的文章"利用ubuntu-app-platform提供的platform接口来减小Qt应用大小"来安装并使用ubuntu-app-platform:platform.具体来说,我们必须进行如下的安装:

$ sudo snap install ubuntu-app-platform

我们在terminal中打入:
$ snapcraft
就可以把我们的应用打包为snap格式.我们使用如下的命令来进行安装:
$ sudo snap install sina-webapp_1.0_amd64.snap --dangerous
等我们安装好后,我们可以发现:

liuxg@liuxg:~$ snap list
Name                 Version  Rev  Developer  Notes
amazon-webapp        1.3      x1              -
azure                0.1      x2              -
core                 16.04.1  714  canonical  -
hello-world          6.3      27   canonical  -
sina-webapp          1.0      x1              -
snappy-debug         0.26     25   canonical  -
ubuntu-app-platform  1        22   canonical  -

我们的sian-webapp已经被成功安装好了.在这里面,我们也可以发现ubuntu-app-platform及core两个snap应用.在我们的应用中,由于我们定义了如下的plug:
  • camera
  • mount-observe
  • network-control
  • content
根据在网址http://snapcraft.io/docs/reference/interfaces里的介绍,我们发现这些接口必须是手动连接的,所以我们必须使用如下的命令:

$ sudo snap connect sina-webapp:platform ubuntu-app-platform:platform
$ sudo snap connect sina-webapp:camera core:camera
$ sudo snap connect sina-webapp:network-control core:network-control
$ sudo snap connect sina-webapp:mount-observe core:mount-observe

通过上面的命令,我们进行了手动的连接.如果由于我们重新安装或其它原因在我们运行我们的应用时出现诸如:

You need to connect the ubuntu-app-platform package with your application   
to reuse shared assets, please run:  
snap install ubuntu-app-platform  
snap connect sina-webapp:platform ubuntu-app-platform:platform  

这样的错误信息,我们需要使用如下的工具:
$ sudo /usr/lib/snapd/snap-discard-ns sina-webapp  
来清除先前的设置,然后在重新运行我们的应用之前,我们再手动连接我们上面所列出来的接口.

我们可以在我们的Desktop的dash中找到我们的应用的图标,并运行.





整个项目的源码在:https://github.com/liu-xiao-guo/sina-webapp.我们可以使用如下的命令从商店来下载这个应用:

$ sudo snap install sina-webapp --beta




作者:UbuntuTouch 发表于2017/1/22 14:09:32 原文链接
阅读:316 评论:0 查看评论

Read more
UbuntuTouch

[原]如何提高编译snap应用的速度

在我们编译打包snap应用时,我们时常会发现在我们的代码或snapcraft.yaml中每次做一次小的改动后,重新运行snapcraft命令时,都会从Ubuntu archive中重新下载所需要的包.如果一个包很大的话,这需要很长的时间才可以完成.如果是在Desktop的情况下,我们有时可以使用VPN来解决这个问题.这种情况特别是发生在我们需要使用ARM板子进行编译打包的时候,因为我在这些板子上甚至不能运行VPN.那么我们如何来解决这个问题呢?

很幸运的是,我们的同事ogra帮我们设计了一个叫做packageproxy的snap包.我们可以通过如下的命令来安装:

$ sudo snap install packageproxy

安装完后,我们可以通过snap list来发现:

liu-xiao-guo@localhost:~$ snap list
Name            Version       Rev  Developer  Notes
classic         16.04         17   canonical  devmode
core            16.04.1       716  canonical  -
grovepi-server  1.0           x1              devmode
packageproxy    0.1           3    ogra       -
pi2             16.04-0.17    29   canonical  -
pi2-kernel      4.4.0-1030-3  22   canonical  -

在我们的ARM板子,比如树莓派中,我们通过安装classic应用,进入到classic的环境中:

$ sudo snap install classic --devmode --edge
$ sudo classic

当然具体的步骤,我们可以参照文章"如何为树莓派安装Ubuntu Core并在Snap系统中进行编译".在进入到我们的classic环境后,我们需要多/etc/apt中的sources.list文件进行修改.为了保险起见,我们首先可以通过如下的命令来保存原先的sources.list文件

(classic)liu-xiao-guo@localhost:/etc/apt$ sudo cp sources.list sources.list.bak

这样以前的文件被保存于sources.list.bak文件中.如果我们打开sources.list文件,我们可以看见它的内容如下:

sources.list

# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://ports.ubuntu.com/ubuntu-ports/ xenial universe
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates universe
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://ports.ubuntu.com/ubuntu-ports/ xenial multiverse
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial multiverse
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-updates multiverse
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted universe multiverse
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu xenial partner
# deb-src http://archive.canonical.com/ubuntu xenial partner

deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security main restricted
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security universe
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security universe
deb http://ports.ubuntu.com/ubuntu-ports/ xenial-security multiverse
# deb-src http://ports.ubuntu.com/ubuntu-ports/ xenial-security multiverse

显然,在上面的文件中,所有的源都指向http://ports.ubuntu.com/ubuntu-ports/.也就是说每次我们重新编译我们的snap应用时,它都会从上面的地址进行下载.如果一个包很大的话,它就会造成我们的编译的时间过长.这显然不是我们所期望的.如果,我们把上面的http://ports.ubuntu.com/ubuntu-ports/换成http://localhost:9999/ubuntu-ports/,那么整个sources.list文件的内容如下:

sources.list

# See http://help.ubuntu.com/community/UpgradeNotes for how to upgrade to
# newer versions of the distribution.
deb http://localhost:9999/ubuntu-ports/ xenial main restricted
# deb-src http://localhost:9999/ubuntu-ports/ xenial main restricted

## Major bug fix updates produced after the final release of the
## distribution.
deb http://localhost:9999/ubuntu-ports/ xenial-updates main restricted
# deb-src http://localhost:9999/ubuntu-ports/ xenial-updates main restricted

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team. Also, please note that software in universe WILL NOT receive any
## review or updates from the Ubuntu security team.
deb http://localhost:9999/ubuntu-ports/ xenial universe
# deb-src http://localhost:9999/ubuntu-ports/ xenial universe
deb http://localhost:9999/ubuntu-ports/ xenial-updates universe
# deb-src http://localhost:9999/ubuntu-ports/ xenial-updates universe

## N.B. software from this repository is ENTIRELY UNSUPPORTED by the Ubuntu
## team, and may not be under a free licence. Please satisfy yourself as to
## your rights to use the software. Also, please note that software in
## multiverse WILL NOT receive any review or updates from the Ubuntu
## security team.
deb http://localhost:9999/ubuntu-ports/ xenial multiverse
# deb-src http://localhost:9999/ubuntu-ports/ xenial multiverse
deb http://localhost:9999/ubuntu-ports/ xenial-updates multiverse
# deb-src http://localhost:9999/ubuntu-ports/ xenial-updates multiverse

## N.B. software from this repository may not have been tested as
## extensively as that contained in the main release, although it includes
## newer versions of some applications which may provide useful features.
## Also, please note that software in backports WILL NOT receive any review
## or updates from the Ubuntu security team.
deb http://localhost:9999/ubuntu-ports/ xenial-backports main restricted universe multiverse
# deb-src http://localhost:9999/ubuntu-ports/ xenial-backports main restricted universe multiverse

## Uncomment the following two lines to add software from Canonical's
## 'partner' repository.
## This software is not part of Ubuntu, but is offered by Canonical and the
## respective vendors as a service to Ubuntu users.
# deb http://archive.canonical.com/ubuntu xenial partner
# deb-src http://archive.canonical.com/ubuntu xenial partner

deb http://localhost:9999/ubuntu-ports/ xenial-security main restricted
# deb-src http://localhost:9999/ubuntu-ports/ xenial-security main restricted
deb http://localhost:9999/ubuntu-ports/ xenial-security universe
# deb-src http://localhost:9999/ubuntu-ports/ xenial-security universe
deb http://localhost:9999/ubuntu-ports/ xenial-security multiverse
# deb-src http://localhost:9999/ubuntu-ports/ xenial-security multiverse

也就是说,每当我们重新下载我们的包的时候,它将从我们的本地地址http://localhost:9999/ubuntu-ports/进行下载.
  • 如果这个包曾经被下载过,那么packageproxy将帮我们从本地的cache中直接提取,从而不需要重新下载
  • 如果这个包从来没有被现在过,那么packageproxy将帮助我们从网上进行下载,并保存于本地以备以后重复使用
为了能够在命令行中进行修改sources.list文件,我们可以使用如下的命令:

sudo sed -i 's/http:\/\/ports.ubuntu.com\/ubuntu-ports/http:\/\/localhost:9999\/ubuntu-ports/g' /etc/apt/sources.list

这显然是一种非常好的方法.在第一编译的时候,它可能需要一些时间.但是以后的编译,它可以直接从本地提取从而加速我们的编译的速度.
在我们设置完上面的步骤后,我们可以通过如下的命令来进行系统的更新及安装:

$ sudo apt-get update
$ sudo apt install snapcraft git-core build-essential

这样我们就安装好我们的编译的环境了.通过这样的配置过后,在第一次编译我的应用时,如果需要的包从来没有下载过,就会慢一些.第二次编译我们的应用时,就会发现速度快很多.当然,我们可以把我们的地址指向某一个设备的IP地址,而不使用localhost,从而使大家从同一个设备中提取所需要的包.这种方法适合于网路环境比较差的时候.特别适合一些hackathon活动.作为一个展示的例子http://paste.ubuntu.com/23789982/,我们可以看到在clean项目后,编译的速度大大提高了.

如果在使用过程中,出现如下的错误:

(classic)liu-xiao-guo@localhost:~$ sudo apt-get update
Err:1 http://localhost:9999/ubuntu-ports xenial InRelease
  Could not connect to localhost:9999 (127.0.0.1). - connect (111: Connection refused) [IP: 127.0.0.1 9999]
Err:2 http://localhost:9999/ubuntu-ports xenial-updates InRelease
  Unable to connect to localhost:9999: [IP: 127.0.0.1 9999]
Err:3 http://localhost:9999/ubuntu-ports xenial-backports InRelease
  Unable to connect to localhost:9999: [IP: 127.0.0.1 9999]
Err:4 http://localhost:9999/ubuntu-ports xenial-security InRelease
  Unable to connect to localhost:9999: [IP: 127.0.0.1 9999]

这种情况可能是由于packageproxy在运行时出现一些问题,我们可以通过删除在如下地址下的文件来解决:

liu-xiao-guo@localhost:/var/snap/packageproxy/3$ ls
approx.conf  config.yaml  hosts.allow  hosts.deny  lockfile.lock  var

我们可以删除上面的lockfile.lock来解决这个问题.

另外,这种方法也适合在Ubuntu Desktop下的snap编译打包,我们只需要把上面的"ubuntu-ports"修改为"ubuntu"即可.这个练习就留给开发者.

如果大家想删除所有已经下载的包以减少存储空间:

  • 使用snap remove packageproxy命令来删除这个应用
  • 删除rm -rf /var/snap/packageproxy/3/var/cache/approx/*所有的文件









作者:UbuntuTouch 发表于2017/1/13 10:04:38 原文链接
阅读:568 评论:4 查看评论

Read more
UbuntuTouch

Socket.io可以使得我们的服务器和客户端进行双向的实时的数据交流。它比HTTP来说更具有传输数据量少的优点。同样地,websocket也具有同样的优点。你可以轻松地把你的数据发送到服务器,并收到以事件为驱动的响应,而不用去查询。在今天的教程中,我们来讲一下如何利用socket.io和websocket来做一个双向的通讯。


1)创建一个socket.io的服务器


首先我们先看一下我完成的一个项目:


我们首先看一下我们的snapcraft.yaml文件:

snapcraft.yaml

name: socketio
version: "0.1"
summary: A simple shows how to make use of socket io
description: socket.io snap example

grade: stable
confinement: strict

apps:
  socket:
    command: bin/socketio
    daemon: simple
    plugs: [network-bind]

parts:
  nod:
    plugin: nodejs
    source: .
   

这是一个nodejs的项目。我们使用了nodejs的plugin。我们的package.json文件如下:

package.json

{
  "name": "socketio",
  "version": "0.0.1",
  "description": "Intended as a nodejs app in a snap",
  "license": "GPL-3.0",
  "author": "xiaoguo, liu",
  "private": true,
  "bin": "./app.js",
  "dependencies": {
    "express": "^4.10.2",
    "nodejs-websocket": "^1.7.1",
    "socket.io": "^1.3.7"
  }
}

由于我们需要使用到webserver,所有我们安装了express架构包。另外,我们使用到socket.io及websocket,所有,我们把这些包都打入到我们的snap包中。

再来看看我们的应用app.js的设计:

app.js

#!/usr/bin/env node

var express = require('express');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);	

app.get('/', function(req, res){
   res.sendFile(__dirname + '/www/index.html');
});

app.use(express.static(__dirname + '/www'));

//Whenever someone connects this gets executed
io.on('connection', function(socket){
  console.log('A user connected');
  
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  io.emit('light-sensor-value', '' + value);
	  // console.log("value: " + value)
	  
	  // This is another way to send data
	  socket.send(value);
  }, 2000); 

  //Whenever someone disconnects this piece of code executed
  socket.on('disconnect', function () {
    console.log('A user disconnected');
  });

});

http.listen(4000, function(){
  console.log('listening on *:4000');
});

var ws = require("nodejs-websocket")

console.log("Going to create the server")

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};
 
// Scream server example: "hi" -> "HI!!!" 
var server = ws.createServer(function (conn) {
	
    console.log("New connection")
	var connected = true;
    
    conn.on("text", function (str) {
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    
    conn.on("close", function (code, reason) {
        console.log("Connection closed")
        connected = false
    })
        	
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  var data = '{"data":"{0}"}'.format(value)
	  if (connected){
		conn.send(data);
	  }
  }, 2000); 	
}).listen(4001)

在代码的第一部分,我们创建了一个webserver,它使用的端口地址是4000。我们也同时启动了socket.io服务器,等待客户端的连接。一旦有一个连接的话,我们使用如下的代码每过一段时间来发送一些数据:

//Whenever someone connects this gets executed
io.on('connection', function(socket){
  console.log('A user connected');
  
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  io.emit('light-sensor-value', '' + value);
	  // console.log("value: " + value)
	  
	  // This is another way to send data
	  socket.send(value);
  }, 2000); 

  //Whenever someone disconnects this piece of code executed
  socket.on('disconnect', function () {
    console.log('A user disconnected');
  });

});

虽然这些数据是一些随机的,但是我们主要用来展示它是如何工作的。在实际的应用中,这些数据可以是从一些传感器中得到的。在我们的客户端中,我们可以打开webserver运行的地址:


我们可以看到数据不断地进来,并在我们的客户端中显示出来。具体的设计请参考在www目录中的index.html文件。


2)创建一个websocket的服务器


在我们的app.js中,我们利用如下的代码来实现一个websocket的服务器。端口地址为4001。

app.js


var ws = require("nodejs-websocket")

console.log("Going to create the server")

String.prototype.format = function() {
    var formatted = this;
    for (var i = 0; i < arguments.length; i++) {
        var regexp = new RegExp('\\{'+i+'\\}', 'gi');
        formatted = formatted.replace(regexp, arguments[i]);
    }
    return formatted;
};
 
// Scream server example: "hi" -> "HI!!!" 
var server = ws.createServer(function (conn) {
	
    console.log("New connection")
	var connected = true;
    
    conn.on("text", function (str) {
        console.log("Received "+str)
        conn.sendText(str.toUpperCase()+"!!!")
    })
    
    conn.on("close", function (code, reason) {
        console.log("Connection closed")
        connected = false
    })
        	
  setInterval(function(){
	  var value = Math.floor((Math.random() * 1000) + 1);
	  var data = '{"data":"{0}"}'.format(value)
	  if (connected){
		conn.send(data);
	  }
  }, 2000); 	
}).listen(4001)

同样地,一旦有个连接,我们每隔两秒钟发送一个数据到我们的客户端。为了说明问题方便,我们设计了一个QML的客户端。

Main.qml


import QtQuick 2.4
import Ubuntu.Components 1.3
import Ubuntu.Components.Pickers 1.3
import Qt.WebSockets 1.0
import QtQuick.Layouts 1.1

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "dialer.liu-xiao-guo"

    width: units.gu(60)
    height: units.gu(85)

    function interpreteData(data) {
        var json = JSON.parse(data)
        console.log("Websocket data: " + data)

        console.log("value: " + json.data)
        mainHand.value = json.data
    }

    WebSocket {
        id: socket
        url: input.text
        onTextMessageReceived: {
            console.log("something is received!: " + message);
            interpreteData(message)
        }

        onStatusChanged: {
            if (socket.status == WebSocket.Error) {
                console.log("Error: " + socket.errorString)
            } else if (socket.status == WebSocket.Open) {
                // socket.sendTextMessage("Hello World....")
            } else if (socket.status == WebSocket.Closed) {
            }
        }
        active: true
    }

    Page {
        header: PageHeader {
            id: pageHeader
            title: i18n.tr("dialer")
        }

        Item {
            anchors {
                top: pageHeader.bottom
                left: parent.left
                right: parent.right
                bottom: parent.bottom
            }

            Column {
                anchors.fill: parent
                spacing: units.gu(1)
                anchors.topMargin: units.gu(2)

                Dialer {
                    id: dialer
                    size: units.gu(30)
                    minimumValue: 0
                    maximumValue: 1000
                    anchors.horizontalCenter: parent.horizontalCenter

                    DialerHand {
                        id: mainHand
                        onValueChanged: console.log(value)
                    }
                }


                TextField {
                    id: input
                    width: parent.width
                    text: "ws://192.168.1.106:4001"
                }

                Label {
                    id: value
                    text: mainHand.value
                }
            }
        }
    }
}

运行我们的服务器及客户端:



我们可以看到我们数值在不断地变化。这个客户端的代码在:https://github.com/liu-xiao-guo/dialer

在这篇文章中,我们展示了如何利用socket.io及websocket来进行双向的实时的通讯。在很多的物联网的应用中,我们可以充分利用这些通讯协议来更好地设计我们的应用。

作者:UbuntuTouch 发表于2017/2/7 16:07:16 原文链接
阅读:235 评论:3 查看评论

Read more
UbuntuTouch

LXD作为一容器的hypervisor,它对LXC提供了更多的新的用户体验.在今天的教程中,我们来介绍如何利用LXD来在不同的Ubuntu Desktop版本下编译我们的snap应用.


1)安装LXD及命令行工具


我们可以参照链接来安装我们的LXD:https://linuxcontainers.org/lxd/getting-started-cli/.为了方便,我们可以利用已经做好的Ubuntu Image:

liuxg@liuxg:~$ lxc launch ubuntu:yakkety
Creating flying-snake
Starting flying-snake

在这里,我们创建了一个叫做flying-snake的容器.这个名字是自动生产的.它是基于Ubuntu 16.10的yakkety.
如果你想有一个自己的容器的名称,你也可以使用如下的命令来生产:

$ lxc launch ubuntu:yakkety foobar

这里的foobar将是我们生成的容器的名称而不是像上面自动生成的flying-snake.

我们可以利用如下的命令来查看:

liuxg@liuxg:~$ lxc list
+----------------------+---------+-------------------+------+------------+-----------+
|         NAME         |  STATE  |       IPV4        | IPV6 |    TYPE    | SNAPSHOTS |
+----------------------+---------+-------------------+------+------------+-----------+
| flying-snake         | RUNNING | 10.0.1.143 (eth0) |      | PERSISTENT | 0         |
+----------------------+---------+-------------------+------+------------+-----------+
| immortal-feline      | STOPPED |                   |      | PERSISTENT | 0         |
+----------------------+---------+-------------------+------+------------+-----------+
| vivid-x86-armhf      | STOPPED |                   |      | PERSISTENT | 0         |
+----------------------+---------+-------------------+------+------------+-----------+
| xenial-desktop-amd64 | STOPPED |                   |      | PERSISTENT | 0         |
+----------------------+---------+-------------------+------+------------+-----------+

2)创建一个用户


我们可以利用如下的命令来创建一个属于自己的用户:

liuxg@liuxg:~$ lxc exec flying-snake -- adduser liuxg
Adding user `liuxg' ...
Adding new group `liuxg' (1001) ...
Adding new user `liuxg' (1001) with group `liuxg' ...
Creating home directory `/home/liuxg' ...
Copying files from `/etc/skel' ...
Enter new UNIX password: 
Retype new UNIX password: 
passwd: password updated successfully
Changing the user information for liuxg
Enter the new value, or press ENTER for the default
	Full Name []: liuxg
	Room Number []: 
	Work Phone []: 
	Home Phone []: 
	Other []: 
Is the information correct? [Y/n] y

请注意这里的flying-snake为我们刚才创建的container的名称.开发者必须根据自己的名称进行选择.我为这个container创建了一个叫做liuxg的用户.为用户添加管理员权限:

liuxg@liuxg:~$ lxc exec flying-snake -- adduser liuxg sudo
Adding user `liuxg' to group `sudo' ...
Adding user liuxg to group sudo
Done.

$ lxc exec flying-snake -- visudo
通过上面的命令,启动编辑器,并在文件的最后,加入:

<username>   ALL=(ALL) NOPASSWD: ALL



注意这里的liuxg是我们刚才创建的用户名.开发者需要替换为自己的用户名.

更新系统并安装所需要的工具:

$ lxc exec flying-snake -- apt update -qq
$ lxc exec flying-snake -- apt upgrade -qq
$ lxc exec flying-snake -- apt install -qq -y snapcraft build-essential


3)登陆并编译我们的应用


我们可以通过如下的命令来登陆:

$ lxc exec flying-snake -- sudo -iu liuxg

注意这里的liuxg是我们之前创建的用户.

liuxg@liuxg:~$ lxc exec flying-snake -- sudo -iu liuxg
To run a command as administrator (user "root"), use "sudo <command>".
See "man sudo_root" for details.

liuxg@flying-snake:~$ 
liuxg@flying-snake:~$ ls -al
total 20
drwxr-xr-x 2 liuxg liuxg 4096 Jan  4 02:52 .
drwxr-xr-x 4 root  root  4096 Jan  4 02:52 ..
-rw-r--r-- 1 liuxg liuxg  220 Jan  4 02:52 .bash_logout
-rw-r--r-- 1 liuxg liuxg 3771 Jan  4 02:52 .bashrc
-rw-r--r-- 1 liuxg liuxg  655 Jan  4 02:52 .profile
liuxg@flying-snake:~$ mkdir apps
liuxg@flying-snake:~$ cd apps/
liuxg@flying-snake:~/apps$ git clone https://github.com/liu-xiao-guo/alias
Cloning into 'alias'...
remote: Counting objects: 4, done.
remote: Compressing objects: 100% (4/4), done.
remote: Total 4 (delta 0), reused 4 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), done.
Checking connectivity... done.
liuxg@flying-snake:~/apps$ ls
alias
liuxg@flying-snake:~/apps$ cd alias/
liuxg@flying-snake:~/apps/alias$ ls
hello.sh  snapcraft.yaml
liuxg@flying-snake:~/apps/alias$ snapcraft 
Preparing to pull aliases 
Pulling aliases 
Preparing to build aliases 
Building aliases 
Staging aliases 
Priming aliases 
Snapping 'my-alias' |                                                                
Snapped my-alias_0.1_amd64.snap

我们可以看到我们已经在yakkety (16.10)的环境中把我们的应用打包为一个snap.

我们可以利用 lxc file pull命令来把我们的容器里的文件拷入到我们的host:

lxc file pull first/etc/hosts .
我们可以利用:

$ lxc stop flying-snake

来停止我们的container.

liuxg@liuxg:~/tmp$ lxc stop flying-snake
liuxg@liuxg:~/tmp$ lxc list
+----------------------+---------+------+------+------------+-----------+
|         NAME         |  STATE  | IPV4 | IPV6 |    TYPE    | SNAPSHOTS |
+----------------------+---------+------+------+------------+-----------+
| flying-snake         | STOPPED |      |      | PERSISTENT | 0         |
+----------------------+---------+------+------+------------+-----------+
| immortal-feline      | STOPPED |      |      | PERSISTENT | 0         |
+----------------------+---------+------+------+------------+-----------+
| vivid-x86-armhf      | STOPPED |      |      | PERSISTENT | 0         |
+----------------------+---------+------+------+------------+-----------+
| xenial-desktop-amd64 | STOPPED |      |      | PERSISTENT | 0         |
+----------------------+---------+------+------+------------+-----------+

具体的操作可以参阅文章:https://linuxcontainers.org/lxd/getting-started-cli/








作者:UbuntuTouch 发表于2017/1/4 11:50:37 原文链接
阅读:494 评论:0 查看评论

Read more
UbuntuTouch

[原]为自己的snap应用添加变量

在很多snap应用开发的时候,我们可以使用我们自己的一个wrapper,并在这个wrapper中指定一些变量从而能够使得我们的应用能够正常地运行。这个特性也特别适合在移植有些snap应用中需要特别设定一些路径到我们snap应用的一些可读写目录中从而避免安全的问题。那么我们怎么实现这个功能呢?


我们先来看一下我们做的一个例程:

https://github.com/liu-xiao-guo/helloworld-env

snapcraft.yaml

name: hello
version: "1.0"
summary: The 'hello' of snaps
description: |
    This is a simple snap example that includes a few interesting binaries
    to demonstrate snaps and their confinement.
    * hello-world.env  - dump the env of commands run inside app sandbox

grade: stable
confinement: strict
type: app  #it can be gadget or framework
icon: icon.png

apps:
 env:
   command: bin/env
   environment:
     VAR1: $SNAP/share
     VAR2: "hello, the world"
 evil:
   command: bin/evil
 sh:
   command: bin/sh

parts:
 hello:
  plugin: dump
  source: .

在上面的例子中,在“env”命令中,我们添加了environment项。在它的里面,我们定义了两个环境变量:VAR1及VAR2。
打包我们的应用,同时执行我们的命令“hello.env”。

$ hello.env | grep VAR
VAR1=$SNAP/share
VAR2=hello, the world

在这里,我们可以看出来我们在没有使用脚本的情况下,为我们的应用添加了两个环境变量VAR1及VAR2。


作者:UbuntuTouch 发表于2017/2/20 10:33:47 原文链接
阅读:96 评论:0 查看评论

Read more
UbuntuTouch

在先前的文章"利用snapweb来管理我们的Ubuntu Core应用"中,我们可以看到有些应用可以显示一个自己独特的应用图标,而另外一些应用只显示一个缺省的Ubuntu Logo图标.这其中的原因是因为我们在snapcraft.yaml文件中缺少定义icon.


我们来看一下我已经创建好的一个项目:

https://github.com/liu-xiao-guo/helloworld-icon

它的snapcraft.yaml的定义如下:

snapcraft.yaml


name: hello-icon
version: "1.0"
summary: The 'hello-world' of snaps
description: |
    This is a simple snap example that includes a few interesting binaries
    to demonstrate snaps and their confinement.
    * hello-world.env  - dump the env of commands run inside app sandbox
    * hello-world.evil - show how snappy sandboxes binaries
    * hello-world.sh   - enter interactive shell that runs in app sandbox
    * hello-world      - simply output text
grade: stable
confinement: strict
type: app  #it can be gadget or framework
icon: icon.png

apps:
 env:
   command: bin/env
 evil:
   command: bin/evil
 sh:
   command: bin/sh

parts:
 hello:
  plugin: dump
  source: .

在这里我们定义了:

icon: icon.png

 

在我们打包完我们的应用,并安装好它.我们重新打开snapweb来查看:



在这里,我们可以看到最新的图标.通过这样的方法,我们可以为我们的snap应用创建一个属于自己的图标.


作者:UbuntuTouch 发表于2017/2/6 9:02:57 原文链接
阅读:224 评论:0 查看评论

Read more
UbuntuTouch

对于有些snap应用来说,我们很希望在snap安装时能够运行我们的一段脚本来做一些我们想要做的事,比如创建一个文件夹等.那么我们如何能得到这个事件呢?在我们的先前的文章"如何为我们的Ubuntu Core应用进行设置"中,我们已经展示了如何设置我们的snap应用.在那里面的configure脚本在设置时会被调用.事实上,它在安装时也会被自动调用.下面,我们以如下的例子来说明:

https://github.com/liu-xiao-guo/helloworld-install

在上面的例子中,我们的configure脚本如下:

configure

#!/bin/sh

echo "This is called during the installation!"
exit 1

这是一个非常简单的脚本程序.在我们的安装过程中,它返回的值是"1",表明它是失败的.那么这个应用将不被成功安装:

liu-xiao-guo@localhost:~/apps/helloworld-install$ sudo snap install *.snap --dangerous
error: cannot perform the following tasks:
- Run configure hook of "hello-install" snap if present (This is called during the installation!)
liu-xiao-guo@localhost:~/apps/helloworld-install$ snap list
Name            Version       Rev  Developer  Notes
classic         16.04         17   canonical  devmode
core            16.04.1       716  canonical  -
grovepi-server  1.0           x1              devmode
packageproxy    0.1           3    ogra       -
pi2             16.04-0.17    29   canonical  -
pi2-kernel      4.4.0-1030-3  22   canonical  -
snapweb         0.21.2        25   canonical  -

显然通过上面的展示,helloworld-install没有被安装到我们的系统中去.
如果我们把configure脚本修改为:

configure

#!/bin/sh

echo "This is called during the installation!"
exit 0

这个脚本的返回值为"0",表明它的安装是成功的.

liu-xiao-guo@localhost:~/apps/helloworld-install$ sudo snap install *.snap --dangerous
hello-install 1.0 installed
liu-xiao-guo@localhost:~/apps/helloworld-install$ snap list
Name            Version       Rev  Developer  Notes
classic         16.04         17   canonical  devmode
core            16.04.1       716  canonical  -
grovepi-server  1.0           x1              devmode
hello-install   1.0           x1              -
packageproxy    0.1           3    ogra       -
pi2             16.04-0.17    29   canonical  -
pi2-kernel      4.4.0-1030-3  22   canonical  -
snapweb         0.21.2        25   canonical  -
liu-xiao-guo@localhost:~/apps/helloworld-install$ vi /var/log/syslog
liu-xiao-guo@localhost:~/apps/helloworld-install$ sudo vi /var/log/syslog

我们可以在系统的/var/log/syslog中找到这个脚本运行时的输出:



显然脚本在安装时有被正常运行.我们可以通过运行这样一个hook来对我们的应用做一些初始化,从而为接下来的应用的运行铺好基础.

作者:UbuntuTouch 发表于2017/1/16 10:30:29 原文链接
阅读:265 评论:0 查看评论

Read more
UbuntuTouch

在先前的文章"如何为我们的Ubuntu Core应用进行设置 "中,我们通过copy plugin的方法把我们想要的congfigure文件拷入到我们所需要的目录中.具体的实现是这样的:

snapcraft.yaml

parts:  
 hello:  
  plugin: copy  
  files:  
    ./bin: bin  
 config:  
  plugin: dump  
  source: .  
  organize:  
    configure: meta/hooks/configure  

由于在snapcraft 2.25版本以后,它提供了对hook的支持,所有,我们只需要要在我们的项目的根目录中建立一个叫做snap/hooks的目录,并把我们的configure文件拷入即可:

liuxg@liuxg:~/snappy/desktop/helloworld-hook$ tree -L 4
.
├── bin
│   ├── createfile
│   ├── createfiletohome
│   ├── echo
│   ├── env
│   ├── evil
│   └── sh
├── setup
│   ├── gui
│   │   ├── helloworld.desktop
│   │   └── helloworld.png
│   └── license.txt
├── snap
│   └── hooks
│       └── configure
└── snapcraft.yaml

有了这样的文件架构后,snapcraft会自动帮我们把configure文件考入到meta/hooks文件目录下.下面是我们的prime目录里的内容:

liuxg@liuxg:~/snappy/desktop/helloworld-hook/prime$ tree -L 3
.
├── bin
│   ├── createfile
│   ├── createfiletohome
│   ├── echo
│   ├── env
│   ├── evil
│   └── sh
├── command-createfiletohome.wrapper
├── command-createfile.wrapper
├── command-env.wrapper
├── command-evil.wrapper
├── command-hello-world.wrapper
├── command-sh.wrapper
├── meta
│   ├── gui
│   │   ├── helloworld.desktop
│   │   └── helloworld.png
│   ├── hooks
│   │   └── configure
│   └── snap.yaml
└── snap
    └── hooks
        └── configure

我们必须记住这个功能只是在snapcraft 2.25以上的版本中才有的.我们可以看到在meta/hooks/中有一个叫做configure的文件.

我们安装好这个snap应用,并执行如下的命令:

$ sudo snap set hello username=foo password=bar

我们可以通过如下的命令来获得这个值:

$ sudo snap get hello username
foo

显然,我们得到我们设置的值.整个源码在:https://github.com/liu-xiao-guo/helloworld-hook.另外一个例程也可以在我们的snapcraft项目中的hooks找到.

更多阅读:https://github.com/snapcore/snapcraft/blob/master/docs/hooks.md.就想文章中介绍的那样,我们也可以利用另外一种方法来实现.具体的例子见pyhooks.这种方法的好处是可以使用python语言来进行设置.运行结果如下:

liuxg@liuxg:~$ sudo snap set pyhooks fail=true
error: cannot perform the following tasks:
- Run configure hook of "pyhooks" snap (Failing as requested.)
liuxg@liuxg:~$ sudo snap set pyhooks fail=false


更多阅读:https://snapcraft.io/docs/build-snaps/hooks




作者:UbuntuTouch 发表于2017/1/20 14:05:49 原文链接
阅读:239 评论:0 查看评论

Read more
UbuntuTouch

[原]微软azure云在Ubuntu Core中的应用

在今天的教程中,我们来展示如何在Ubuntu Core中使用azure的IoT hub来开发我们的应用.Azure IoT Hub目前提供了一个框架对我们的IoT设备进行管理,并可以通过预置解决方案来展示我们的数据.在今天的文章中,我们将介绍如何把我们的设备连接到远程监视预配置解决方案中.


1)预配远程监视预配置解决方案


我们可以按照在微软的官方文档:


来创建一个我们的预配置解决方案,并最终形成向如下的配置:



这里我的解决方案的名称叫做"sensors".







如果在我们的IoT设备中有数据传上来的话,我们可以在右边的"遥测历史记录"中看到这些数据.这些数据通常是以曲线的形式来表现出来的.
在创建设备的过程中,我们需要记录下来在下面画面中的数据,以便我们在代码实现中使用:



我们也可以打开azure.cn来查看我们已经创建的所有的资源:









这里显示的"连接字符串-主秘钥"对我们以后的编程是非常有用的.需要特别留意一下.


2)生成以C语言开发的snap应用


在这一节中,我们将展示如下如何使用C语言来开发一个客户端,并最终形成一个snap应用.这个应用将和我们在上一节中所形成的远程监视预配置解决方案进行通信.我们在Ubuntu 16.04的Desktop中开发snap应用.如果大家对snap开发的安装还是不很熟悉的话,请参阅我的文章来安装好自己的环境.就像文章中介绍的那样,我们先安装必要的组件包:

$ sudo apt-get install cmake gcc g++

将 AzureIoT 存储库添加到计算机:
$ sudo add-apt-repository ppa:aziotsdklinux/ppa-azureiot
$ sudo apt-get update
安装 azure-iot-sdk-c-dev 包:
$ sudo apt-get install -y azure-iot-sdk-c-dev
这样,我们就安装好了我们所需要的组件包.由于一些原因,在我们编译我们的例程中,会出现一些的错误,所以我们必须做如下的手动修改:
/usr/include/azureiot/inc$ sudo mv azure_c_shared_utility ..
有了这个改动,就可以确保我们在如下的编译中不会出现头文件找不到的情况.

我们先来看看我已经做好的一个项目:

snapcraft.yaml

name: remote-monitor 
version: '0.1' 
summary: This is a remote-monitor snap for azure
description: |
  This is a remote-monitor sample snap for azure

grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots

apps:
  remote-monitor:
    command: bin/sample_app
    plugs: [network]

parts:
  remote:
    plugin: cmake
    source: ./src

这个项目是一个cmake项目.由于我们的包的名称和我们的应用名称是一样的,所在我们运行我们的应用时,我们可以直接打入remote-monitorming来运行我们的应用.在做任何改变之前,我们打开remote_monitoring.c文件,并注意一下的代码:

static const char* deviceId = "mydevice";
static const char* deviceKey = "[Device Key]";
static const char* hubName = "sensorsf8f61";
static const char* hubSuffix = "azure-devices.cn";

这里的解释是:

static const char* deviceId = "[Device Id]";
static const char* deviceKey = "[Device Key]";
static const char* hubName = "[IoTHub Name]";
static const char* hubSuffix = "[IoTHub Suffix, i.e. azure-devices.net]";

我们需要根据我们自己的账号的情况替换这些值.在实际运用中,我们可以修改在remote_monitoring.c中的如下的代码:

while (1)
{
	unsigned char*buffer;
	size_t bufferSize;
	
	srand(time(NULL));
	int r = rand() % 50;  
	int r1 = rand() % 55;
	int r2 = rand() % 50;
	printf("r: %d, r1: %d, r2: %d\n", r, r1, r2);
	thermostat->Temperature = r;
	thermostat->ExternalTemperature = r1;
	thermostat->Humidity = r2;
	
	(void)printf("Sending sensor value Temperature = %d, Humidity = %d\r\n", thermostat->Temperature, thermostat->Humidity);

	if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity, thermostat->ExternalTemperature) != CODEFIRST_OK)
	{
		(void)printf("Failed sending sensor value\r\n");
	}
 ...
}
来把我们所需要的数据传上去.在这里,我们随意写了一些随机的数据.

注意这里的"deviceKey"是我们在上节中图片中所展示的那个"Device Key".
我们在termnial中直接打入如下的命令:
$ snapcraft
这样就形成了我们的项目的snap包.我们可以通过如下的命令来进行安装:

liuxg@liuxg:~/snappy/desktop/azure/remote-monitor$ sudo snap install remote-monitor_0.1_amd64.snap --dangerous
[sudo] password for liuxg: 
remote-monitor 0.1 installed

liuxg@liuxg:~$ snap list
Name            Version  Rev  Developer  Notes
azure           0.1      x1              -
core            16.04.1  714  canonical  -
hello           1.0      x1              devmode
hello-world     6.3      27   canonical  -
hello-xiaoguo   1.0      x1              -
remote-monitor  0.1      x2    
显然我们的remote-monitor已经被成功安装.我们在terminal中打入如下的命令:
liuxg@liuxg:~$ remote-monitor 
IoTHubClient accepted the message for delivery
r: 30, r1: 37, r2: 4
Sending sensor value Temperature = 30, Humidity = 4
IoTHubClient accepted the message for delivery
r: 45, r1: 23, r2: 35
Sending sensor value Temperature = 45, Humidity = 35
IoTHubClient accepted the message for delivery
r: 16, r1: 39, r2: 25
Sending sensor value Temperature = 16, Humidity = 25
IoTHubClient accepted the message for delivery
r: 16, r1: 33, r2: 14
Sending sensor value Temperature = 16, Humidity = 14
IoTHubClient accepted the message for delivery
r: 20, r1: 29, r2: 32

显然我们的客户端应用在不断地向azure IoT Hub发送数据.我们可以通过https://www.azureiotsuite.cn/来查看我们已经收到的数据.



在下面我们可以看到设备数据的最大值及最小值的变化.
如果大家想把这个应用在树莓派等的ARM设备上运行的话,请参阅我的文章"如何为树莓派安装Ubuntu Core并在Snap系统中进行编译".具体的安装和这里介绍的是一样的.请开发者自己去试.


3)生成以nodejs开发的snap应用


在这一节中,我们将介绍如何使用nodejs来开发我们的snap应用.我们可以参阅文章"适用于 Node.js 的 Azure IoT 中心入门".就像这篇文章中所介绍的那样,我们最感兴趣的是它里面介绍的第三个控制台应用程序SimulatedDevice.js.

SimulatedDevice.js

#!/usr/bin/env node

var clientFromConnectionString = require('azure-iot-device-amqp').clientFromConnectionString;
var Message = require('azure-iot-device').Message;

var connectionString = 'HostName=sensorsf8f61.azure-devices.cn;DeviceId=mydevice;SharedAccessKey={Device Key}';

var client = clientFromConnectionString(connectionString);

function printResultFor(op) {
  return function printResult(err, res) {
    if (err) console.log(op + ' error: ' + err.toString());
    if (res) console.log(op + ' status: ' + res.constructor.name);
  };
}

var connectCallback = function (err) {
  if (err) {
    console.log('Could not connect: ' + err.amqpError);
  } else {
    console.log('Client connected');

    // Create a message and send it to the IoT Hub every second
    setInterval(function(){
        var temp = 10 + (Math.random() * 4);
        var windSpeed = 10 + (Math.random() * 4);
        var data = JSON.stringify({ deviceId: 'mydevice', temp: temp, windSpeed: windSpeed});
        var message = new Message(data);
        console.log("Sending message: " + message.getData());
        client.sendEvent(message, printResultFor('send'));

    }, 5000);
  }
};

client.open(connectCallback);

注意在上面的代码中,我们需要手动修改如下的connectionString:
var connectionString = 'HostName=sensorsf8f61.azure-devices.cn;DeviceId=mydevice;SharedAccessKey={yourdevicekey}';
就像在文章中介绍的那样,它的定义为:

var connectionString = 'HostName={youriothostname};DeviceId=myFirstNodeDevice;SharedAccessKey={yourdevicekey}';

我们需要根据我们在第一节中设置的那些参数来修改上面的字符串.大家可以参阅我的项目:

snapcraft.yaml

name: azure 
version: '0.1' # just for humans, typically '1.2+git' or '1.3.2'
summary: This is an azure snap app
description: |
  This is an azure client snap to send a message

grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots

apps:
  azure:
    command: bin/send
    plugs: [network]

parts:
  node:
    plugin: nodejs
    source: .

同样我们可以打入snapcraft命令来生产相应的包,并进行安装:

liuxg@liuxg:~/snappy/desktop/azurenode-snap$ snap list
Name            Version  Rev  Developer  Notes
azure           0.1      x2              -
core            16.04.1  714  canonical  -
hello           1.0      x1              devmode
hello-world     6.3      27   canonical  -
hello-xiaoguo   1.0      x1              -
remote-monitor  0.1      x2         

我们可以直接运行azure命令:

liuxg@liuxg:~/snappy/desktop/azurenode-snap$ azure
Client connected
Sending message: {"deviceId":"mydevice","temp":11.826184131205082,"windSpeed":11.893792165443301}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":10.594819721765816,"windSpeed":10.54138664342463}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":11.27814894542098,"windSpeed":10.962828870862722}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":13.068702490068972,"windSpeed":10.28670579008758}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":11.723079251125455,"windSpeed":12.173830625601113}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":12.595101269893348,"windSpeed":12.120747512206435}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":11.431507185101509,"windSpeed":11.76255036983639}
send status: MessageEnqueued
Sending message: {"deviceId":"mydevice","temp":12.488932724110782,"windSpeed":13.200456796213984}
send status: MessageEnqueued

我们可以通过https://www.azureiotsuite.cn/来查看我们已经收到的数据:



我们在上面可以看到Temp及Wind Speed的曲线.同样地,如果大家想把这个应用在树莓派等的ARM设备上运行的话,请参阅我的文章"如何为树莓派安装Ubuntu Core并在Snap系统中进行编译".请开发者自己去试.


作者:UbuntuTouch 发表于2017/1/19 16:59:05 原文链接
阅读:220 评论:0 查看评论

Read more
UbuntuTouch

在我们的应用设计中,我们通过会选择一些临时的文件目录来存储我们的文件,比如在Linux中的tmp文件目录.那么在我们的snap设计中,我们应该利用哪个文件目录来存储我们的文件呢?答案是我们可以选择XDG_RUNTIME_DIR,当然这也依赖于开发者自己的选择.


我们先来看一下我的一个做好的例程:

https://github.com/liu-xiao-guo/helloworld-fifo

它的snapcraft.yaml文件如下:


name: hello
version: "1.0"
summary: The 'hello-world' of snaps
description: |
    This is a simple snap example that includes a few interesting binaries
    to demonstrate snaps and their confinement.
    * hello-world.env  - dump the env of commands run inside app sandbox
    * hello-world.evil - show how snappy sandboxes binaries
    * hello-world.sh   - enter interactive shell that runs in app sandbox
    * hello-world      - simply output text
grade: stable
confinement: strict
type: app  #it can be gadget or framework
icon: icon.png

apps:
 fifo:
   command: bin/fifo
 env:
   command: bin/env
 evil:
   command: bin/evil
 sh:
   command: bin/sh
 hello-world:
   command: bin/echo
 createfile:
   command: bin/createfile
 createfiletohome:
   command: bin/createfiletohome
 writetocommon:
   command: bin/writetocommon

parts:
 hello:
  plugin: dump
  source: .

在这里,我们设计了一个叫做fifo的应用.它的脚本具体如下:

#!/bin/bash

echo "Going to make a directory at: $XDG_RUNTIME_DIR"
mkdir -p $XDG_RUNTIME_DIR

echo "Create a file at the location..."
cd $XDG_RUNTIME_DIR
pwd
touch thisfile

if [ $? == 0 ]; then
	echo "The file is successfully created!"
else
	echo "The file is not successfully created!"
fi

我首先创建一个目录,并在目录中创建一个文件.显示如下:

liuxg@liuxg:~$ hello.fifo 
Going to make a directory at: /run/user/1000/snap.hello
Create a file at the location...
/run/user/1000/snap.hello
The file is successfully created!

显然这个应用的运行是没有任何的permission的问题的.它是完全可以访问并进行读写的位置.这个位置可以被我们的应用程序用来进行FIFO的操作.

我们实际上也可以运行我在应用中的env这个应用来展示所有的环境变量:

liuxg@liuxg:~$ hello.env | grep XDG_RUNTIME_DIR
XDG_RUNTIME_DIR=/run/user/1000/snap.hello


当然,我们也可以使用/tmp目录来作为临时存储文件目录.这个目录对于每个snap应用来说都是独特的,也就是每个应用有一个自己的独立的tmp目录.但是我们我们都可以按照/tmp的方式去访问.这个文件的位置可以在我们的桌面电脑的/tmp目录下找到。它的文件目录有点像/tmp/snap.1000_snap.hello.fifo_5BpMiB/tmp。

我们可以使用如下的代码来检验这个:

fifo

#!/bin/bash

echo "Going to make a directory at: $XDG_RUNTIME_DIR"
mkdir -p $XDG_RUNTIME_DIR

echo "Create a file at the location..."
cd $XDG_RUNTIME_DIR
pwd
touch thisfile

if [ $? == 0 ]; then
	echo "The file is successfully created!"
else
	echo "The file is not successfully created!"
fi

cd /tmp
pwd
echo "Haha" > test.txt

if [ $? == 0 ]; then
	echo "The test.txt file is successfully created!"
else
	echo "The test.txt file is not successfully created!"
fi


作者:UbuntuTouch 发表于2017/2/4 11:37:04 原文链接
阅读:193 评论:0 查看评论

Read more
UbuntuTouch

基于开发者程路的项目:https://github.com/dawndiy/electronic-wechat-snap,我对该项目做了一些小的修改.但最终把electronic-wechat打包为snap应用.


1)方案一


在整个方案中,我们直接把一个稳定编译好的发布直接下载打包.这个项目的源码:

snapcraft.yaml


name: electronic-wechat
version: '1.4.0'
summary: A better WeChat on macOS and Linux. Built with Electron.
description: |
  Electronic WeChat is a unoffical WeChat client. A better WeChat on
  macOS and Linux. Built with Electron.
grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots

apps:
  electronic-wechat:
    command: desktop-launch $SNAP/wechat.wrapper
    plugs:
      - unity7
      - opengl
      - network
      - pulseaudio
      - home
      - browser-support
      - gsettings
      - x11

parts:
  electronic-wechat:
    plugin: dump
    source: https://github.com/geeeeeeeeek/electronic-wechat/releases/download/v1.4.0/linux-x64.tar.gz
    stage-packages:
      - libnss3
      - fontconfig-config
      - gnome-themes-standard
      - fonts-wqy-microhei
      - libasound2-data
      - fcitx-frontend-gtk2
      - overlay-scrollbar-gtk2
      - libatk-adaptor
      - libcanberra-gtk-module
    filesets:
      no-easy-install-files:
        - -usr/sbin/update-icon-caches
        - -README.md
    stage:
      - $no-easy-install-files
    prime:
      - $no-easy-install-files

  wechat-copy:
    plugin: dump
    source: .
    filesets:
      wechat.wrapper: wechat.wrapper
    after: 
      - electronic-wechat
      - desktop-gtk2

在这里,我们直接在地址https://github.com/geeeeeeeeek/electronic-wechat/releases/download/v1.4.0/linux-x64.tar.gz下载已经编译好的稳定的版本,并进行打包.这里我们可以利用dump plugin来帮我们进行安装.

2)方案二


我们可以利用最新的代码来编译,并打包.这个项目的源码在:


snapcraft.yaml


name: electronic-wechat
version: '1.4.0'
summary: A better WeChat on macOS and Linux. Built with Electron.
description: |
  Electronic WeChat is a unoffical WeChat client. A better WeChat on
  macOS and Linux. Built with Electron.
grade: stable # must be 'stable' to release into candidate/stable channels
confinement: strict # use 'strict' once you have the right plugs and slots

apps:
  electronic-wechat:
    command: desktop-launch $SNAP/wechat.wrapper
    plugs:
      - unity7
      - opengl
      - network
      - pulseaudio
      - home
      - browser-support
      - gsettings
      - x11

parts:
  electronic-wechat:
    plugin: nodejs
    source-type: git
    source: https://github.com/geeeeeeeeek/electronic-wechat/
    source-branch: production
    npm-run:
      - build:linux
    install: cp -r dist $SNAPCRAFT_PART_INSTALL
    stage-packages:
      - libnss3
      - fontconfig-config
      - gnome-themes-standard
      - fonts-wqy-microhei
      - libasound2-data
      - fcitx-frontend-gtk2
      - overlay-scrollbar-gtk2
      - libatk-adaptor
      - libcanberra-gtk-module
    filesets:
      no-easy-install-files:
        - -usr/sbin/update-icon-caches
        - -README.md
    stage:
      - $no-easy-install-files
    prime:
      - $no-easy-install-files

  wechat-copy:
    plugin: dump
    source: .
    filesets:
      wechat.wrapper: wechat.wrapper
    after: 
      - electronic-wechat
      - desktop-gtk2

最新的代码在地址https://github.com/geeeeeeeeek/electronic-wechat/可以找到.我们利用nodejs plugin来帮我们进行打包.在这里,我们使用了snapcraft的Scriplets来覆盖我们的nodejs plugin中的install:

   install: cp -r dist $SNAPCRAFT_PART_INSTALL

对于上面的npm-run那一句,我们甚至也可以删除,并用snapcraft中的Scriplets来实现:

build: npm run build:linux

我们在项目的根目录下打入如下的命令:

$ snapcraft

它将最终帮我们生成我们所需要的.snap文件.我们可以安装到我们的系统中:

$ sudo snap install electronic-wechat_1.4.0_amd64.snap --dangerous

liuxg@liuxg:~$ snap list
Name                 Version  Rev  Developer  Notes
core                 16.04.1  888  canonical  -
electronic-wechat    1.4.0    x1              -
hello-world          6.3      27   canonical  -
hello-xiaoguo        1.0      x1              -
snappy-debug         0.28     26   canonical  -
ubuntu-app-platform  1        22   canonical  -

我们可以看到electronic-wechat已经被成功安装到我的电脑中.运行我们的应用:








作者:UbuntuTouch 发表于2017/2/3 16:12:02 原文链接
阅读:178 评论:0 查看评论

Read more
UbuntuTouch

在今天的文章中,我们将介绍如何把一个HTML5的应用打包为一个snap应用。我们知道有很多的HTML5应用,但是我们如何才能把它们打包为我们的snap应用呢?特别是在Ubuntu手机手机开发的时候,有很多的已经开发好的HTML5游戏。我们可以通过我们今天讲的方法来把先前的click HTML5应用直接打包为snap应用,并可以在我们的Ubuntu桌面电脑上进行运行。当然,今天介绍的方法并不仅限于Ubuntu手机开发的HTML应用。这里的方法也适用于其它的HTML5应用。




1)HTML5应用


首先,我们看一下我之前做过的一个为Ubuntu手机而设计的一个HTML5应用。它的地址为:


你可以通过如下的方式得到这个代码:

bzr branch lp:~liu-xiao-guo/debiantrial/wuziqi

在这个应用中,我们只关心的是在它www目录里面的内容。这个项目的所有文件如下:

$ tree
.
├── manifest.json
├── wuziqi.apparmor
├── wuziqi.desktop
├── wuziqi.png
├── wuziqi.ubuntuhtmlproject
└── www
    ├── css
    │   └── app.css
    ├── images
    │   ├── b.png
    │   └── w.png
    ├── index.html
    └── js
        └── app.js

我们希望把在www里面的内容能够最终打包到我们的snap应用中去。

2)打包HTML5应用为snap


为了能够把我们的HTML5应用打包为一个snap应用,我们可以在项目的根目录下打入如下的命令:

$ snapcraft init

上面的命令将在我们的当前的目录下生产一个新的snap目录,并在里面生一个叫做snapcraft.yaml的文件。这实际上是一个模版。我们可以通过修改这个snapcraft.yaml文件来把我们的应用进行打包。运行完上面的命令后,文件架构如下:

$ tree
.
├── manifest.json
├── snap
│   └── snapcraft.yaml
├── wuziqi.apparmor
├── wuziqi.desktop
├── wuziqi.png
├── wuziqi.ubuntuhtmlproject
└── www
    ├── css
    │   └── app.css
    ├── images
    │   ├── b.png
    │   └── w.png
    ├── index.html
    └── js
        └── app.js

我们通过修改snapcraft.yaml文件,并最终把它变为:

snapcraft.yaml


name: wuziqi
version: '0.1'
summary: Wuziqi Game. It shows how to snap a html5 app into a snap
description: |
  This is a Wuziqi Game. There are two kind of chesses: white and black. Two players
  play it in turn. The first who puts the same color chesses into a line is the winner.

grade: stable
confinement: strict

apps:
  wuziqi:
    command: webapp-launcher www/index.html
    plugs:
      - browser-sandbox
      - camera
      - mir
      - network
      - network-bind
      - opengl
      - pulseaudio
      - screen-inhibit-control
      - unity7

plugs:
  browser-sandbox:
    interface: browser-support
    allow-sandbox: false
  platform:
    interface: content
    content: ubuntu-app-platform1
    target: ubuntu-app-platform
    default-provider: ubuntu-app-platform

parts:
  webapp:
    after: [ webapp-helper, desktop-ubuntu-app-platform ]
    plugin: dump
    source: .
    stage-packages:
      - ubuntu-html5-ui-toolkit
    organize:
      'usr/share/ubuntu-html5-ui-toolkit/': www/ubuntu-html5-ui-toolkit
    prime:
      - usr/*
      - www/*

这里的解释如下:
  • 由于这是一个HTML5的应用,我们可以通过webapp-helper来启动我们的应用。在我们的应用中我们使用被叫做webapp-helper的remote part
  • 由于在Ubuntu的手机中,web的底层部分是由Qt进行完成的,所以我们必须要把Qt也打包到我们的应用中。但是由于Qt库是比较大的,我们可以通过ubuntu-app-platform snap应用通过它提供的platform接口来得到这些Qt库。开发者可以参阅我们的文章https://developer.ubuntu.com/en/blog/2016/11/16/snapping-qt-apps/
  • 在我们的index.html文件中,有很多的诸如<script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/core.js"></script>。这显然和ubuntu-html5-ui-toolkit有关,所以,我们必须把ubuntu-html5-ui-toolkit这个包也打入到我们的应用中。这个我们通过stage-packages来安装ubuntu-html5-ui-toolkit包来实现
  • 我们通过organize把从ubuntu-html5-ui-toolkit中安装的目录ubuntu-html5-ui-toolkit重组到我们项目下的www目录中以便index.html文件引用
我们再来看看我们的原始的index.html文件:

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>An Ubuntu HTML5 application</title>
    <meta name="description" content="An Ubuntu HTML5 application">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0">

    <!-- Ubuntu UI Style imports - Ambiance theme -->
    <link href="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/css/appTemplate.css" rel="stylesheet" type="text/css" />

    <!-- Ubuntu UI javascript imports - Ambiance theme -->
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/fast-buttons.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/core.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/buttons.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/dialogs.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/page.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/pagestacks.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/tab.js"></script>
    <script src="/usr/share/ubuntu-html5-ui-toolkit/0.1/ambiance/js/tabs.js"></script>

    <!-- Application script -->
    <script src="js/app.js"></script>
    <link href="css/app.css" rel="stylesheet" type="text/css" />

  </head>

  <body>
        <div class='test'>
          <div>
              <img src="images/w.png" alt="white" id="chess">
          </div>
          <div>
              <button id="start">Start</button>
          </div>
        </div>

        <div>
            <canvas width="640" height="640" id="canvas" onmousedown="play(event)">
                 Your Browser does not support HTML5 canvas
            </canvas>
        </div>
  </body>
</html>

从上面的代码中,在index.hml文件中它引用的文件是从/usr/share这里开始的。在一个confined的snap应用中,这个路径是不可以被访问的(因为一个应用只能访问自己安装在自己项目根目录下的文件)。为此,我们必须修改这个路径。我们必须把上面的/usr/share/的访问路径改变为相对于本项目中的www目录的访问路径:

    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/fast-buttons.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/core.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/buttons.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/dialogs.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/page.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/pagestacks.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/tab.js"></script>
    <script src="ubuntu-html5-ui-toolkit/0.1/ambiance/js/tabs.js"></script>

这就是为什么我们在之前的snapcraft.yaml中看到的:

parts:
  webapp:
    after: [ webapp-helper, desktop-ubuntu-app-platform ]
    plugin: dump
    source: .
    stage-packages:
      - ubuntu-html5-ui-toolkit
    organize:
      'usr/share/ubuntu-html5-ui-toolkit/': www/ubuntu-html5-ui-toolkit
    prime:
      - usr/*
      - www/*

在上面,我们通过organize把ubuntu-html5-ui-toolkit安装后的目录重新组织并移到我的项目的www目录中,从而使得这里的文件可以直接被我们的项目所使用。我们经过打包后的文件架构显示如下:

$ tree -L 3
.
├── bin
│   ├── desktop-launch
│   └── webapp-launcher
├── command-wuziqi.wrapper
├── etc
│   └── xdg
│       └── qtchooser
├── flavor-select
├── meta
│   ├── gui
│   │   ├── wuziqi.desktop
│   │   └── wuziqi.png
│   └── snap.yaml
├── snap
├── ubuntu-app-platform
├── usr
│   ├── bin
│   │   └── webapp-container
│   └── share
│       ├── doc
│       ├── ubuntu-html5-theme -> ubuntu-html5-ui-toolkit
│       └── webbrowser-app
└── www
    ├── css
    │   └── app.css
    ├── images
    │   ├── b.png
    │   └── w.png
    ├── index.html
    ├── js
    │   ├── app.js
    │   └── jquery.min.js
    └── ubuntu-html5-ui-toolkit
        └── 0.1

在上面,我们可以看出来ubuntu-html5-ui-toolkit现在处于在www文件目录下,可以直接被我们的项目所使用。

我们在项目的根目录下打入如下的命令:

$ snapcraft

如果一切顺利的话,我们可以得到一个.snap文件。我们可以通过如下的命令来进行安装:

$ sudo snap install wuziqi_0.1_amd64.snap --dangerous

安装完后,由于我们使用了content sharing的方法来访问Qt库,所以,我们必须安装如下的snap:

$ snap install ubuntu-app-platform 
$ snap connect wuziqi:platform ubuntu-app-platform:platform

执行上面的命令后,我们可以看到:

$ snap interfaces
Slot                          Plug
:account-control              -
:alsa                         -
:avahi-observe                -
:bluetooth-control            -
:browser-support              wuziqi:browser-sandbox
:camera                       -
:core-support                 -
:cups-control                 -
:dcdbas-control               -
:docker-support               -
:firewall-control             -
:fuse-support                 -
:gsettings                    -
:hardware-observe             -
:home                         -
:io-ports-control             -
:kernel-module-control        -
:libvirt                      -
:locale-control               -
:log-observe                  snappy-debug
:lxd-support                  -
:modem-manager                -
:mount-observe                -
:network                      downloader,wuziqi
:network-bind                 socketio,wuziqi
:network-control              -
:network-manager              -
:network-observe              -
:network-setup-observe        -
:ofono                        -
:opengl                       wuziqi
:openvswitch                  -
:openvswitch-support          -
:optical-drive                -
:physical-memory-control      -
:physical-memory-observe      -
:ppp                          -
:process-control              -
:pulseaudio                   wuziqi
:raw-usb                      -
:removable-media              -
:screen-inhibit-control       wuziqi
:shutdown                     -
:snapd-control                -
:system-observe               -
:system-trace                 -
:time-control                 -
:timeserver-control           -
:timezone-control             -
:tpm                          -
:uhid                         -
:unity7                       wuziqi
:upower-observe               -
:x11                          -
ubuntu-app-platform:platform  wuziqi
-                             wuziqi:camera
-                             wuziqi:mir

当然在我们的应用中,我们也使用了冗余的plug,比如上面的camera及mir等。我们可以看到wuziqi应用和其它Core及ubuntu-app-platform snap的连接情况。在确保它们都连接好之后,我们可以在命令行中打入如下的命令:

$ wuziqi

它将启动我们的应用。当然,我们也可以从我们的Desktop的dash中启动我们的应用:






作者:UbuntuTouch 发表于2017/2/13 10:16:55 原文链接
阅读:128 评论:0 查看评论

Read more
UbuntuTouch

我们在先前的文章"如何把一个qmake的Ubuntu手机应用打包为一个snap应用"中体会了如何把一个qmake的项目打包为一个snap应用.在今天的教程中,我们利用Qt Creator来创建一个项目,并最终把我们的应用打包为一个snap项目.在打包的过程中,我们可以体会在snapcraft中的scriplets


1)创建一个Qt Helloworld项目


首先,我们打开我们的Qt Creator:







这样我们就创建了一个最简单的一个helloworld应用.


2)创建snapcraft.yaml文件


我们在项目的根目录下,打入如下的命令:
$ snapcraft init
上面的命令将会为我们在当前目录下生成一个叫做snap的目录(snapcraft version 2.26,之前的版本没有创建这个snap目录).

liuxg@liuxg:~/snappy/desktop/qtapp$ tree -L 3
.
├── main.cpp
├── mainwindow.cpp
├── mainwindow.h
├── mainwindow.ui
├── qtapp.pro
├── qtapp.pro.user
├── README.md
└── snap
    └── snapcraft.yaml

所有文件的架构如上面所示.我们可以通过编辑修改这个snapcraft.yaml文件:

snapcraft.yaml

name: qthello 
version: '0.1' 
summary: a demo for qt hello app
description: |
  This is a qt app demo

grade: stable 
confinement: strict 

apps:
  qthello:
    command: desktop-launch $SNAP/opt/myapp/qtapp
    plugs: [home, unity7, x11]

parts:
  project:
    plugin: qmake
    source: .
    qt-version: qt5
    project-files: [qtapp.pro]
    install: |
      install -d $SNAPCRAFT_PART_INSTALL/opt/myapp
      install qtapp $SNAPCRAFT_PART_INSTALL/opt/myapp/qtapp

  integration:
    plugin: nil
    stage-packages:
     - libc6
     - libstdc++6
     - libc-bin
    after: [desktop-qt5]

在这里,我们必须指出的是:

    install: |
      install -d $SNAPCRAFT_PART_INSTALL/opt/myapp
      install qtapp $SNAPCRAFT_PART_INSTALL/opt/myapp/qtapp

由于在原始的qtapp.pro文件中,并没有相应的代码让我们如何去安装我们的qtapp应用文件.我们在这里使用了上面的install来安装我们的应用.根据在Scriplets里的描述:

“install”

The install scriptlet is triggered after the build step of a plugin.

这里的scripts将会在build之后自动被自动执行.它首先创建一个叫做myapp的目录,接着把我们在build目录中的二进制执行文件qtapp安装到myapp目录下.这样就最终形成了我们的snap包.

我们安装好qthello应用,并执行:






在这个snap应用中,我们把对Qt所有的库的依赖都打包到一个包里,这样我们最终的snap包的大小很大.如果开发者想减少这个Qt应用的大小的话,开发者可以参阅文章"利用ubuntu-app-platform提供的platform接口来减小Qt应用大小"来减小整个应用的大小.





作者:UbuntuTouch 发表于2017/2/3 14:25:12 原文链接
阅读:133 评论:0 查看评论

Read more
UbuntuTouch

[原]Ubuntu Core 配置

Core snap提供了一些配置的选项。这些选项可以允许我们定制系统的运行。就像和其它的snap一样,Core snap的配置选项可以通过snap set命令来实现:

$ snap set core option=value


选项目前的值可以通过snap get命令来获取:

$ snap get core option
value


下面我们来展示如何来禁止系统的ssh服务:

警告:禁止ssh将会使得我们不能在默认的方式下访问Ubuntu Core系统。如果我们不提供其它的方式来管理或登陆系统的话,你的系统将会是一个砖。建议你可以正在系统中设置一个用户名及密码,以防止你不能进入到系统。如果你有其它的方式进入到系统,也是可以的。当我们进入到Ubunutu Core系统中后,我们可以使用如下的命令来创建一个用户名及密码,这样我们可以通过键盘及显示器的方式来登陆。

$ sudo passwd <ubuntu-one id>
<password>

设置的选项接受如下的值:

  • false (默认):启动ssh服务。ssh服务将直接对连接请求起作用
  • true:禁止ssh服务。目前存在的ssh连接将继续保留,但是任何更进一步的连接将是不可能的
$ snap set core service.ssh.disable=true
当我们执行完上面的命令后,任何更进一步的访问将被禁止:

$ ssh liu-xiao-guo@192.168.1.106
ssh: connect to host 192.168.1.106 port 22: Connection refused

$ snap set core service.ssh.disable=false
执行上面的命令后将使得我们可以重新连接ssh。
我们可以通过如下的命令来获得当前的值:

$ snap get core service.ssh.disable
false

更多阅读:https://docs.ubuntu.com/core/en/reference/core-configuration

作者:UbuntuTouch 发表于2017/2/15 10:29:38 原文链接
阅读:68 评论:0 查看评论

Read more