Android Emacs 下使用 org-protocol 的一些问题

Android 的 Emacs 好像没法在 termux 环境下调用 emacsclient,但是可以使用 adb 打开文件:

am start -a android.intent.action.VIEW -n org.gnu.emacs/.EmacsOpenActivity -d file:///storage/emulated/0/1.txt org.gnu.emacs

因此也可以调用 org-protocol:

am start -a android.intent.action.VIEW -n org.gnu.emacs/.EmacsOpenActivity -d org-protocol://test?a=a org.gnu.emacs

但是要先 advice 以下函数,因为传给 emacs 的参数前面会加上 emacs 的家目录导致 org-protocol 识别不了

(with-eval-after-load 'org-protocol
  (define-advice org-protocol-check-filename-for-protocol
      (:filter-args (args) compat-android)
    "Remove prefix when called by intent."
    (let ((h (getenv "HOME"))
          (f (car args)))
      (when (string-prefix-p (format "%s/%s:/" h org-protocol-the-protocol) f)
        (setcar args (substring f (1+ (length h)))))
      args)))

也就可以使用 Tasker 或者 Fooview 这种自动化或手势软件方便地执行命令: image

但有个问题就是每次运行,Emacs 都会弹到前台来,假如我想后台执行命令大伙有什么想法吗,另外我没搞懂怎么使用 termux 普通的权限执行 am 命令,理论上应该是可以的

(用这个开 http 服务器能实现后台执行还能方便地返回数据,但还是想用自带的功能GitHub - skeeto/emacs-web-server: Extensible Emacs HTTP 1.1 server


我写个完整的配置,可能上面没说清楚,Android 需要执行上面的 advice:

(progn
         (require 'server)
         (unless server-process
           (server-start))
         (require 'org-protocol)
         (defun my/test-org (info) (message "yes") t)
         (add-to-list 'org-protocol-protocol-alist '("test-org" :protocol "test" :function my/test-org :kill-client t)))

然后在 termux 运行这个就能 “yes” 了

am start -a android.intent.action.VIEW -n org.gnu.emacs/.EmacsOpenActivity -d org-protocol://test?a=a org.gnu.emacs

主要场景是在没法运行 emacsclient 的情况下调用 elisp,比如浏览器使用 Tampermonkey、安卓启动 Activity 等(大伙都没这需求的吗,还是我这方式有点邪门

可能原因和adb类似,如果要后台调用不显示界面,需要用adb shell service call这种形式,但是就要求应用本身提供了对应功能的service才行,直接用am是会打开对应的activity

另外用termux执行打开应用是不需要什么特殊权限吧,还是我没有明白你的意思

你没理解错,是我描述错了,termux 里没有问题,我是拿 Fooview 里的 shell 运行的 am 报这个错导致我以为 termux 里的 am 也有这个权限问题 :smiling_face_with_tear:

你要是想在其它应用的命令行接口调用am,我知道的办法就是像emacs一样,androidmanifest.xml声明里面加上这个

android:sharedUserId="com.termux"

再重新编译,可能还要注意签名一致的问题,如果没记错的话

然后就可以正常使用了

这个应用是闭源的,可能没法改 androidmanifest.xml ,但其实主要想后台执行 emacs 的命令,听你上一条回复好像目前是没法的,大概只能通过 http 了 :smiling_face_with_tear:

可以用一些“曲线”工具来解决编译的问题,如果一定要使用的话

我也不知道emacs是不是提供了你需要的service,可以先用adb shell service list看看有没有emacs相关的内容

1 个赞

adb shell "service list | grep -i emacs" 并没有输出

拿其他工具看了下也只有这个,感觉应该是没有提供的 image

那看来就很难满足你的需求了,或者问一下emacs的开发者,他在论坛里面,看能不能有办法,或者你可以自己克隆一下源码魔改,不过感觉不是那么容易了

我的锅,你那样写应该是对的,可能emacs确实没有相关的service,而且adb shell service本身应该只能查看系统的,这第三方的要不去看源码,要不你去问开发者才行,他的用户名是oldosfan这个

我明天在手机上也试试看

@oldosfan 老哥问一下,Android 的外部应用执行 Emacs 内部的命令有哪些比较好的方式吗,比如系统广播、Service 这些,或者浏览器打开特定格式的 url 如电脑上的 org-protocol。 :smiley: (不太懂安卓开发可能问题有点蠢

1 个赞

查了一下androidmanifest.xml,里面是带了一个service,具体名称是org.gnu.emacs.EmacsService

不懂怎么用这个 :smiling_face_with_tear:

能不能给一个具体的使用场景,我周末试试看

仔细看了一下帖子,大概了解了,今晚尝试一下看行不行

1 个赞

好的好的感谢

这个目前不支持,不过可以通过 shared user ID 调用 emacsclient。

1 个赞

刚刚看到了 OP 说在调用 emacsclient 时遇到了困难。Emacs server 的 socket 默认会在 /data/data/org.gnu.emacs/cache/emacsNNNN 开启,这里的 NNNN 可以用 termux 应用的 UID。

1 个赞

能问一下 emacsclient 的路径吗,还是说要在 termux 里面装一个 emacs,用termux 的 emacsclient 指定这个 socket

/data/data/org.gnu.emacs/lib/libemacsclient.so 是 Emacsclient,在 termux 中可能需要手动指定 socket。

注意,虽然命名为 .so,这个照样是可执行文件。

1 个赞

好的感谢,我试试 :grinning:

function setup_emacsclient(){
  local emacsclient_path="${PREFIX}/bin/emacsclient"
  if ! [ -f "$emacsclient_path" ]; then
    ln -s /data/data/org.gnu.emacs/lib/libemacsclient.so "$emacsclient_path"
  fi
  export EMACS_SOCKET_NAME="/data/data/org.gnu.emacs/cache/emacs10$(whoami | tail -c 4)/server"
}

setup_emacsclient

在 termux 的 .bashrc 加了这个就能正常 emacsclient -e "(message \"aaa\")"

1 个赞