<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0"
  xmlns:atom="http://www.w3.org/2005/Atom"
  xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>ikvarxt 的博客</title>
    <link>https://blog.ikvarxt.me/</link>
    
    <atom:link href="https://blog.ikvarxt.me/rss2.xml" rel="self" type="application/rss+xml"/>
    
    <description></description>
    <pubDate>Fri, 19 Sep 2025 18:50:23 GMT</pubDate>
    <generator>http://hexo.io/</generator>
    
    <item>
      <title>macOS 一键切换 Karabiner Profile 和输入法</title>
      <link>https://blog.ikvarxt.me/one-key-switch-karabine-profile-on-macos</link>
      <guid>https://blog.ikvarxt.me/one-key-switch-karabine-profile-on-macos</guid>
      <pubDate>Sat, 20 Sep 2025 01:55:19 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;为什么&quot;&gt;&lt;a href=&quot;#为什么&quot; class=&quot;headerlink&quot; title=&quot;为什么&quot;&gt;&lt;/a&gt;为什么&lt;/h2&gt;&lt;p&gt;我的电脑配置了交换 Command 键和 Control 键，同时使用 Programmer Dvorak 键位，就导致这是一台何晨</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="为什么"><a href="#为什么" class="headerlink" title="为什么"></a>为什么</h2><p>我的电脑配置了交换 Command 键和 Control 键，同时使用 Programmer Dvorak 键位，就导致这是一台何晨光的电脑，谁都别想用，在我一个人使用的时候固然是非常方便的，但日常工作免不了问大佬问题，大佬可能直接上手操作电脑解决，这时候就尴尬了，才要慌乱的调整键位。</p><p>我用的键位映射软件是 Karabiner-Elements，软件本身就支持 Profile 的功能，允许在多个配置之间切换，我们只需要额外增加一个空白的 Profile 在需要的时候切换过去就好，然后再手动切换输入法。</p><p>但我们可以做到一键切换。</p><h2 id="配置方式"><a href="#配置方式" class="headerlink" title="配置方式"></a>配置方式</h2><p>在 Karabiner 中设置好我们自己定制的 Profile，我这里命名为 <code>ikvarxt</code>，原始没有任何改动的 Profile，命名为 <code>original</code>，我们需要在这两个 Profile 的 Complex Modifications 栏下，增加如下的自定义配置：</p><figure class="highlight json"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br></pre></td><td class="code"><pre><span class="line"><span class="punctuation">&#123;</span></span><br><span class="line">  <span class="attr">&quot;description&quot;</span><span class="punctuation">:</span> <span class="string">&quot;Switch between ikvarxt and original&quot;</span><span class="punctuation">,</span></span><br><span class="line">  <span class="attr">&quot;manipulators&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;basic&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="comment">/* 设置一个 flag 标记,用于单按键切换 Profile */</span></span><br><span class="line">      <span class="attr">&quot;conditions&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;variable_if&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;input_source switched&quot;</span><span class="punctuation">,</span></span><br><span class="line">          <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="number">1</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;from&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="comment">/* 我这里设置为按左下角的 global 键切换 */</span></span><br><span class="line">        <span class="attr">&quot;apple_vendor_top_case_key_code&quot;</span><span class="punctuation">:</span> <span class="string">&quot;keyboard_fn&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;to&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;select_input_source&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="comment">/* 切换到 Programmer Dvorak 输入法 */</span></span><br><span class="line">            <span class="attr">&quot;input_source_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;com.apple.keyboardlayout.Programmer Dvorak&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;language&quot;</span><span class="punctuation">:</span> <span class="string">&quot;^en$&quot;</span></span><br><span class="line">          <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;set_variable&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;input_source switched&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="number">0</span></span><br><span class="line">          <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;to_after_key_up&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="comment">/* 通过 Karabiner 的 cli 操作切换 Profile，主要改为你的 Profile 名称 */</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;shell_command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#x27;/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_cli&#x27; --select-profile &#x27;ikvarxt&#x27;&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">    <span class="punctuation">&#123;</span></span><br><span class="line">      <span class="attr">&quot;type&quot;</span><span class="punctuation">:</span> <span class="string">&quot;basic&quot;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;from&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">        <span class="attr">&quot;apple_vendor_top_case_key_code&quot;</span><span class="punctuation">:</span> <span class="string">&quot;keyboard_fn&quot;</span></span><br><span class="line">      <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;to&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;select_input_source&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="comment">/* 切换为 ABC 输入法 */</span></span><br><span class="line">            <span class="attr">&quot;input_source_id&quot;</span><span class="punctuation">:</span> <span class="string">&quot;com.apple.keylayout.ABC&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;language&quot;</span><span class="punctuation">:</span> <span class="string">&quot;^en$&quot;</span></span><br><span class="line">          <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span><span class="punctuation">,</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;set_variable&quot;</span><span class="punctuation">:</span> <span class="punctuation">&#123;</span></span><br><span class="line">            <span class="attr">&quot;name&quot;</span><span class="punctuation">:</span> <span class="string">&quot;input_source switched&quot;</span><span class="punctuation">,</span></span><br><span class="line">            <span class="attr">&quot;value&quot;</span><span class="punctuation">:</span> <span class="number">1</span></span><br><span class="line">          <span class="punctuation">&#125;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span><span class="punctuation">,</span></span><br><span class="line">      <span class="attr">&quot;to_after_key_up&quot;</span><span class="punctuation">:</span> <span class="punctuation">[</span></span><br><span class="line">        <span class="punctuation">&#123;</span></span><br><span class="line">          <span class="attr">&quot;shell_command&quot;</span><span class="punctuation">:</span> <span class="string">&quot;&#x27;/Library/Application Support/org.pqrs/Karabiner-Elements/bin/karabiner_cli&#x27; --select-profile &#x27;original&#x27;&quot;</span></span><br><span class="line">        <span class="punctuation">&#125;</span></span><br><span class="line">      <span class="punctuation">]</span></span><br><span class="line">    <span class="punctuation">&#125;</span></span><br><span class="line">  <span class="punctuation">]</span></span><br><span class="line"><span class="punctuation">&#125;</span></span><br></pre></td></tr></table></figure><p>有几个需要注意的点：</p><ol><li>两个 Profile 都需要创建 Complex Modifications</li><li>当前在使用的 input_source_id 可以通过 Karabiner-EventViewer 的 Variables 标签页查看</li><li>按键的 keycode 也可以在 Karabiner-EventViewer 中查看，注意要复制完整的 keycode json 值替换 from 字段下的内容</li><li>注意更改 karabiner_cli 命令的 Profile 参数为你的 Profile 名称</li></ol><h2 id="参考"><a href="#参考" class="headerlink" title="参考"></a>参考</h2><ul><li><a href="https://www.reddit.com/r/Karabiner/comments/10xuiqb/switching_between_profiles_and_input_sources/">Switching Between Profiles and Input Sources</a></li></ul>]]></content:encoded>
      
      
      
      <category domain="https://blog.ikvarxt.me/tags/Tips/">Tips</category>
      
      
      <comments>https://blog.ikvarxt.me/one-key-switch-karabine-profile-on-macos#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>git dev tips</title>
      <link>https://blog.ikvarxt.me/git-dev-tips/</link>
      <guid>https://blog.ikvarxt.me/git-dev-tips/</guid>
      <pubDate>Sat, 23 Aug 2025 04:03:17 GMT</pubDate>
      
        
        
      <description>&lt;h2 id=&quot;netrc&quot;&gt;&lt;a href=&quot;#netrc&quot; class=&quot;headerlink&quot; title=&quot;.netrc&quot;&gt;&lt;/a&gt;.netrc&lt;/h2&gt;&lt;p&gt;这个技巧是从公司内部的 gitlab 配置指南中学到的，主要功能是可以非常轻松的记住密码 token，比如 Gi</description>
        
      
      
      
      <content:encoded><![CDATA[<h2 id="netrc"><a href="#netrc" class="headerlink" title=".netrc"></a>.netrc</h2><p>这个技巧是从公司内部的 gitlab 配置指南中学到的，主要功能是可以非常轻松的记住密码 token，比如 GitHub personal access toke。<br>用法：在用户主目录下创建 .netrc 文件, 内容如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">machine github.com</span><br><span class="line">login your_username</span><br><span class="line">password your_access_token</span><br></pre></td></tr></table></figure><p>只需要简单的这样一个文件，后面使用 https 拉取代码，就会自动登录，比配置什么 ssh 密钥方便太多了。</p><h2 id="gitconfig-includeIf"><a href="#gitconfig-includeIf" class="headerlink" title="gitconfig includeIf"></a>gitconfig includeIf</h2><p>在公司的电脑上面我们设定 git 全局用户名为公司的用户名，但我们可能希望在维护开源项目时使用自己的 GitHub 用户名，那么就可以将开源项目放到一个 opensource 目录下，在 <code>~/.gitconfig</code> 中配置如下：</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">[includeIf &quot;gitdir:~/opensource/&quot;]</span><br><span class="line">    path = ~/opensource/.gitconfig</span><br></pre></td></tr></table></figure><p>在 ~&#x2F;opensource&#x2F;.gitconfig 配置里我们就可以定义如下，</p><figure class="highlight plaintext"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">[user]</span><br><span class="line">    name = ikvarxt</span><br><span class="line">    email = hi@ikvarxt.me</span><br></pre></td></tr></table></figure><p>这样在 ~&#x2F;opensource 目录下的所有 git 仓库里面，我们都会以 ikvarxt 这个名称来提交了。切换到其他目录，则会使用全局设置。</p><p>舒服。</p>]]></content:encoded>
      
      
      
      <category domain="https://blog.ikvarxt.me/tags/Tips/">Tips</category>
      
      
      <comments>https://blog.ikvarxt.me/git-dev-tips/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Android Binder 子系统学习随笔</title>
      <link>https://blog.ikvarxt.me/android-binder-learning-note/</link>
      <guid>https://blog.ikvarxt.me/android-binder-learning-note/</guid>
      <pubDate>Thu, 05 Dec 2024 22:07:00 GMT</pubDate>
      
        
        
      <description>&lt;blockquote&gt;
&lt;p&gt;其实本文在 2023 年 5 月写下，一直放着没有整理，直到今天。&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h1 id=&quot;Binder-Driver&quot;&gt;&lt;a href=&quot;#Binder-Driver&quot; class=&quot;headerlink&quot; title</description>
        
      
      
      
      <content:encoded><![CDATA[<blockquote><p>其实本文在 2023 年 5 月写下，一直放着没有整理，直到今天。</p></blockquote><h1 id="Binder-Driver"><a href="#Binder-Driver" class="headerlink" title="Binder Driver"></a>Binder Driver</h1><p>驱动层到底干了什么，binder 框架对应的是 C&#x2F;S之间的通讯，而 binder 是这中间的桥梁，将发送方的信息传递给接收方。binder 处理了这其中底层的数据交换</p><ul><li>打开 binder 设备</li><li>mmap 映射内存：此操作将用户控件的内存映射到内核空间中</li><li>传递客户端与服务端的数据</li><li>托管线程管理</li></ul><h2 id="flat-binder-object"><a href="#flat-binder-object" class="headerlink" title="flat_binder_object"></a>flat_binder_object</h2><p>这是 binder 中用来跨进程传递对象的结构体。</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">struct</span> <span class="title">flat_binder_object</span> &#123;</span></span><br><span class="line">__u32type;</span><br><span class="line">__u32flags;</span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">union</span> &#123;</span></span><br><span class="line"><span class="type">binder_uintptr_t</span>binder; <span class="comment">/* local object */</span></span><br><span class="line">__u32    handle;<span class="comment">/* remote object */</span></span><br><span class="line">&#125;;</span><br><span class="line"><span class="type">binder_uintptr_t</span>cookie;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>其中的 type 为</p><figure class="highlight c"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">enum</span> &#123;</span></span><br><span class="line">    <span class="comment">// 用来标记当前传递的是 binder 实体</span></span><br><span class="line">BINDER_TYPE_BINDER    = B_PACK_CHARS(<span class="string">&#x27;s&#x27;</span>, <span class="string">&#x27;b&#x27;</span>, <span class="string">&#x27;*&#x27;</span>, B_TYPE_LARGE),</span><br><span class="line">BINDER_TYPE_WEAK_BINDER= B_PACK_CHARS(<span class="string">&#x27;w&#x27;</span>, <span class="string">&#x27;b&#x27;</span>, <span class="string">&#x27;*&#x27;</span>, B_TYPE_LARGE),</span><br><span class="line">    <span class="comment">// 用来标记当前传递的是 binder 在 driver 中的引用地址</span></span><br><span class="line">BINDER_TYPE_HANDLE    = B_PACK_CHARS(<span class="string">&#x27;s&#x27;</span>, <span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;*&#x27;</span>, B_TYPE_LARGE),</span><br><span class="line">BINDER_TYPE_WEAK_HANDLE= B_PACK_CHARS(<span class="string">&#x27;w&#x27;</span>, <span class="string">&#x27;h&#x27;</span>, <span class="string">&#x27;*&#x27;</span>, B_TYPE_LARGE),</span><br><span class="line">BINDER_TYPE_FD    = B_PACK_CHARS(<span class="string">&#x27;f&#x27;</span>, <span class="string">&#x27;d&#x27;</span>, <span class="string">&#x27;*&#x27;</span>, B_TYPE_LARGE),</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>当 Server 把 binder 实体传递给 Client 的时候，Server 携带的 <code>flat_binder_object.binder</code> 是 binder 实体在 Server 用户空间的内存，driver 会自动的将此变量存储为 driver 中保存的为 client 创建的 <strong>binder 实体引用</strong>指针，然后再将 <code>flat_binder_object</code> 传递给 client，client 才能将此指针填入到 <code>binder_transation_data</code> 的 <strong>target.handle</strong> 域中，才能正确的像 Server 发起 IPC 请求。</p><h2 id="驱动层的线程管理"><a href="#驱动层的线程管理" class="headerlink" title="驱动层的线程管理"></a>驱动层的线程管理</h2><p>驱动从最开始设计就为多线程做了支持，线程实际在 C&#x2F;S 端去创建，驱动作为管理者通知 C&#x2F;S 端来创建线程、退出线程等。</p><h3 id="问题"><a href="#问题" class="headerlink" title="问题"></a>问题</h3><ul><li>线程用完就会退出吗？</li><li>驱动根据进程有无空闲的线程来决定是否创建线程吗？</li><li>最大线程数就是就是一个 Server 的最大并发吗？</li></ul><h2 id="ServiceManager"><a href="#ServiceManager" class="headerlink" title="ServiceManager"></a>ServiceManager</h2><p>系统中只允许曾在一个 ServiceManager 进程。ServiceManager 只将唯一的服务名称与其在 driver 中的引用号做了映射，其他 client 随用随取，所以他的工作很简单。只有 128K 的缓存空间。</p><h3 id="问题-1"><a href="#问题-1" class="headerlink" title="问题"></a>问题</h3><ul><li>ServiceManager 的线程管理，最大线程数</li></ul><h2 id="debugfs"><a href="#debugfs" class="headerlink" title="debugfs"></a>debugfs</h2><p>存储的位置位于 <code>/sys/kernel/debug/binder</code></p><p>使用方式：</p><ul><li><code>/sys/kernel/debug/binder/proc</code> 查看有哪些进程使用了 binder</li><li><code>transaction_log</code> &amp; <code>transactions</code> 文件查看 binder 的通信信息</li></ul><h1 id="C-层的-Binder"><a href="#C-层的-Binder" class="headerlink" title="C++ 层的 Binder"></a>C++ 层的 Binder</h1><p>Framework 层的 binder 将实现分为 native 和 proxy 两端，native 端对应的是服务端的实现，proxy 端对应的是服务的远程接口，使用服务的 client 将会拿到 proxy 端用来发起 RPC 请求。proxy 和 native 内部通过 binder 协议进行中转。client 调用 Foo.bar() 函数的时候，会将函数号、参数信息传递给 binder driver 中，binder 跨进程访问 native 实现的对应函数。实现 RPC 调用。</p><p><img src="/images/binder_middleware.png" alt="binder 类结构"></p><p>为什么要这么设计。interface 的设计逻辑是什么。</p><p>IInterface 和 IBinder 本质上是同一个层次的抽象。IInterface 承载了服务的借口，IBinder 则标志了这是一个 binder 服务。</p><p>IInterface.h 中定义了如下的模版类：</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> INTERFACE&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BnInterface</span> : <span class="keyword">public</span> INTERFACE, <span class="keyword">public</span> BBinder</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> sp&lt;IInterface&gt;      <span class="title">queryLocalInterface</span><span class="params">(<span class="type">const</span> String16&amp; _descriptor)</span></span>;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> <span class="type">const</span> String16&amp;     <span class="title">getInterfaceDescriptor</span><span class="params">()</span> <span class="type">const</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="keyword">typedef</span> INTERFACE           BaseInterface;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IBinder*            <span class="title">onAsBinder</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br><span class="line"></span><br><span class="line"><span class="comment">// ----------------------------------------------------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="keyword">template</span>&lt;<span class="keyword">typename</span> INTERFACE&gt;</span><br><span class="line"><span class="keyword">class</span> <span class="title class_">BpInterface</span> : <span class="keyword">public</span> INTERFACE, <span class="keyword">public</span> BpRefBase</span><br><span class="line">&#123;</span><br><span class="line"><span class="keyword">public</span>:</span><br><span class="line">    <span class="function"><span class="keyword">explicit</span>                    <span class="title">BpInterface</span><span class="params">(<span class="type">const</span> sp&lt;IBinder&gt;&amp; remote)</span></span>;</span><br><span class="line"></span><br><span class="line"><span class="keyword">protected</span>:</span><br><span class="line">    <span class="keyword">typedef</span> INTERFACE           BaseInterface;</span><br><span class="line">    <span class="function"><span class="keyword">virtual</span> IBinder*            <span class="title">onAsBinder</span><span class="params">()</span></span>;</span><br><span class="line">&#125;;</span><br></pre></td></tr></table></figure><p>我现在认为这两个模版类的作用只是方便开发者实现 BnXXX 和 BpXXX，自动继承自不同的 BBinder 或 BpRefBase。</p><p>BnInterface &amp; BpInterface 继承自用户实现的 IXxxInterface 为了约束 binder 的功能接口作为公共的借口提供给 BpXx 和 BnXxx，实现端与代理端从 BnInterface &amp; BpInterface 才开始分叉。</p><p>为了满足 Binder 的实现规则，</p><ul><li>每一个 binder 服务都需要定义一个唯一的标识符，写作 descriptor，通过 getInterfaceDescriptor() 访问</li><li>为了便于调用者获取到服务借口，公共 Interface 需要定义一个 <code>android::sp&lt;IXXX&gt; asInterface</code> 来返回基类对象指针。</li></ul><p>IInterface.h 实现了如下的宏，用于开发者快速定义</p><figure class="highlight c++"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">// ----------------------------------------------------------------------</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DECLARE_META_INTERFACE(INTERFACE)                                                         \</span></span><br><span class="line"><span class="meta">public:                                                                                           \</span></span><br><span class="line"><span class="meta">    static const ::android::String16 descriptor;                                                  \</span></span><br><span class="line"><span class="meta">    static ::android::sp<span class="string">&lt;I##INTERFACE&gt;</span> asInterface(const ::android::sp<span class="string">&lt;::android::IBinder&gt;</span>&amp; obj); \</span></span><br><span class="line"><span class="meta">    virtual const ::android::String16&amp; getInterfaceDescriptor() const;                            \</span></span><br><span class="line"><span class="meta">    I##INTERFACE();                                                                               \</span></span><br><span class="line"><span class="meta">    virtual ~I##INTERFACE();                                                                      \</span></span><br><span class="line"><span class="meta">    static bool setDefaultImpl(::android::sp<span class="string">&lt;I##INTERFACE&gt;</span> impl);                                 \</span></span><br><span class="line"><span class="meta">    static const ::android::sp<span class="string">&lt;I##INTERFACE&gt;</span>&amp; getDefaultImpl();                                   \</span></span><br><span class="line"><span class="meta">                                                                                                  \</span></span><br><span class="line"><span class="meta">private:                                                                                          \</span></span><br><span class="line"><span class="meta">    static ::android::sp<span class="string">&lt;I##INTERFACE&gt;</span> default_impl;                                              \</span></span><br><span class="line"><span class="meta">                                                                                                  \</span></span><br><span class="line"><span class="meta">public:</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> __IINTF_CONCAT(x, y) (x ## y)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">ifndef</span> DO_NOT_CHECK_MANUAL_BINDER_INTERFACES</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \</span></span><br><span class="line"><span class="meta">    static_assert(internal::allowedManualInterface(NAME),               \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;b/64223827: Manually written binder interfaces are &quot;</span> \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;considered error prone and frequently have bugs. &quot;</span>   \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;The preferred way to add interfaces is to define &quot;</span>   \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;an .aidl file to auto-generate the interface. If &quot;</span>   \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;an interface must be manually written, add its &quot;</span>     \</span></span><br><span class="line"><span class="meta">                  <span class="string">&quot;name to the whitelist.&quot;</span>);                            \</span></span><br><span class="line"><span class="meta">    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)    \</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#<span class="keyword">else</span></span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                       \</span></span><br><span class="line"><span class="meta">    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)    \</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"><span class="meta">#<span class="keyword">endif</span></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Macro to be used by both IMPLEMENT_META_INTERFACE and IMPLEMENT_META_NESTED_INTERFACE</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(ITYPE, INAME, BPTYPE)                     \</span></span><br><span class="line"><span class="meta">    const ::android::String16&amp; ITYPE::getInterfaceDescriptor() const &#123; return ITYPE::descriptor; &#125; \</span></span><br><span class="line"><span class="meta">    ::android::sp<span class="string">&lt;ITYPE&gt;</span> ITYPE::asInterface(const ::android::sp<span class="string">&lt;::android::IBinder&gt;</span>&amp; obj) &#123;        \</span></span><br><span class="line"><span class="meta">        ::android::sp<span class="string">&lt;ITYPE&gt;</span> intr;                                                                 \</span></span><br><span class="line"><span class="meta">        <span class="keyword">if</span> (obj != nullptr) &#123;                                                                      \</span></span><br><span class="line"><span class="meta">            intr = ::android::sp<span class="string">&lt;ITYPE&gt;</span>::cast(obj-&gt;queryLocalInterface(ITYPE::descriptor));        \</span></span><br><span class="line"><span class="meta">            <span class="keyword">if</span> (intr == nullptr) &#123;                                                                 \</span></span><br><span class="line"><span class="meta">                intr = ::android::sp<span class="string">&lt;BPTYPE&gt;</span>::make(obj);                                           \</span></span><br><span class="line"><span class="meta">            &#125;                                                                                      \</span></span><br><span class="line"><span class="meta">        &#125;                                                                                          \</span></span><br><span class="line"><span class="meta">        return intr;                                                                               \</span></span><br><span class="line"><span class="meta">    &#125;                                                                                              \</span></span><br><span class="line"><span class="meta">    ::android::sp<span class="string">&lt;ITYPE&gt;</span> ITYPE::default_impl;                                                      \</span></span><br><span class="line"><span class="meta">    bool ITYPE::setDefaultImpl(::android::sp<span class="string">&lt;ITYPE&gt;</span> impl) &#123;                                        \</span></span><br><span class="line"><span class="meta">        <span class="comment">/* Only one user of this interface can use this function     */</span>                            \</span></span><br><span class="line"><span class="meta">        <span class="comment">/* at a time. This is a heuristic to detect if two different */</span>                            \</span></span><br><span class="line"><span class="meta">        <span class="comment">/* users in the same process use this function.              */</span>                            \</span></span><br><span class="line"><span class="meta">        assert(!ITYPE::default_impl);                                                              \</span></span><br><span class="line"><span class="meta">        <span class="keyword">if</span> (impl) &#123;                                                                                \</span></span><br><span class="line"><span class="meta">            ITYPE::default_impl = std::move(impl);                                                 \</span></span><br><span class="line"><span class="meta">            return true;                                                                           \</span></span><br><span class="line"><span class="meta">        &#125;                                                                                          \</span></span><br><span class="line"><span class="meta">        return false;                                                                              \</span></span><br><span class="line"><span class="meta">    &#125;                                                                                              \</span></span><br><span class="line"><span class="meta">    const ::android::sp<span class="string">&lt;ITYPE&gt;</span>&amp; ITYPE::getDefaultImpl() &#123; return ITYPE::default_impl; &#125;            \</span></span><br><span class="line"><span class="meta">    ITYPE::INAME() &#123;&#125;                                                                              \</span></span><br><span class="line"><span class="meta">    ITYPE::~INAME() &#123;&#125;</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Macro for an interface type.</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE(INTERFACE, NAME)                        \</span></span><br><span class="line"><span class="meta">    const ::android::StaticString16 I##INTERFACE##_descriptor_static_str16(                     \</span></span><br><span class="line"><span class="meta">            __IINTF_CONCAT(u, NAME));                                                           \</span></span><br><span class="line"><span class="meta">    const ::android::String16 I##INTERFACE::descriptor(I##INTERFACE##_descriptor_static_str16); \</span></span><br><span class="line"><span class="meta">    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(I##INTERFACE, I##INTERFACE, Bp##INTERFACE)</span></span><br><span class="line"></span><br><span class="line"><span class="comment">// Macro for &quot;nested&quot; interface type.</span></span><br><span class="line"><span class="comment">// For example,</span></span><br><span class="line"><span class="comment">//   class Parent .. &#123; class INested .. &#123; &#125;; &#125;;</span></span><br><span class="line"><span class="comment">// DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(Parent, Nested, &quot;Parent.INested&quot;)</span></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_NESTED_INTERFACE(PARENT, INTERFACE, NAME)  \</span></span><br><span class="line"><span class="meta">    const ::android::String16 PARENT::I##INTERFACE::descriptor(NAME);                    \</span></span><br><span class="line"><span class="meta">    DO_NOT_DIRECTLY_USE_ME_IMPLEMENT_META_INTERFACE0(PARENT::I##INTERFACE, I##INTERFACE, \</span></span><br><span class="line"><span class="meta">                                                     PARENT::Bp##INTERFACE)</span></span><br><span class="line"></span><br><span class="line"><span class="meta">#<span class="keyword">define</span> CHECK_INTERFACE(interface, data, reply)                         \</span></span><br><span class="line"><span class="meta">    do &#123;                                                                \</span></span><br><span class="line"><span class="meta">      <span class="keyword">if</span> (!(data).checkInterface(this)) &#123; return PERMISSION_DENIED; &#125;   \</span></span><br><span class="line"><span class="meta">    &#125; while (false)                                                     \</span></span><br><span class="line"><span class="meta"></span></span><br><span class="line"></span><br><span class="line"><span class="comment">// ----------------------------------------------------------------------</span></span><br></pre></td></tr></table></figure><p>有了这两个宏之后，开发者只要在接口基类（IXXX）头文件中，使用 <code>DECLARE_META_INTERFACE</code> 宏便完成了需要的组件的声明。然后在 cpp 文件中使用 <code>IMPLEMENT_META_INTERFACE</code> 便完成了这些组件的实现。</p><h2 id="Binder-的初始化"><a href="#Binder-的初始化" class="headerlink" title="Binder 的初始化"></a>Binder 的初始化</h2><p>所有使用到 Binder 的进程在开始使用 Binder 进行 IPC 之前都需要打开 binder 设备并且 mmap 映射内存。这部分逻辑因为是进程共有的，所以定义到了 framework 的 ProcessState 类中。</p><p>ProcessState 实例为单例，进程唯一，进程只需要打开一次 binder 设备与 mmap 映射。</p>]]></content:encoded>
      
      
      
      <category domain="https://blog.ikvarxt.me/tags/Android/">Android</category>
      
      
      <comments>https://blog.ikvarxt.me/android-binder-learning-note/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>在 Android Fragment 中集成 React Native</title>
      <link>https://blog.ikvarxt.me/integrate-react-native-to-android-fragment/</link>
      <guid>https://blog.ikvarxt.me/integrate-react-native-to-android-fragment/</guid>
      <pubDate>Mon, 09 Sep 2024 13:27:38 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;这里想介绍的是如果我们想在一个已有的项目里独立的集成 React Native，可能我只需要一个特定的简单页面通过 React Native 实现动态化，并不想像文档那样接入 React Native 的 gradle 插件来实现。&lt;/p&gt;
&lt;p&gt;先增加 ReactNati</description>
        
      
      
      
      <content:encoded><![CDATA[<p>这里想介绍的是如果我们想在一个已有的项目里独立的集成 React Native，可能我只需要一个特定的简单页面通过 React Native 实现动态化，并不想像文档那样接入 React Native 的 gradle 插件来实现。</p><p>先增加 ReactNative 的依赖到 app 模块的 build.gradle</p><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">dependencies &#123;</span><br><span class="line">   implementation(<span class="string">&quot;com.facebook.react:react-android:0.75.2&quot;</span>)</span><br><span class="line">   implementation(<span class="string">&quot;com.facebook.react:hermes-android:0.75.2&quot;</span>)</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>Sync 项目之后可以实现 ReactNative 的入口 Fragment 文件。</p><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">class</span> <span class="title class_">ReactNativeFragment</span> : <span class="type">Fragment</span>() &#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">lateinit</span> <span class="keyword">var</span> rootView: ReactRootView</span><br><span class="line">    <span class="keyword">private</span> <span class="keyword">lateinit</span> <span class="keyword">var</span> reactInstanceManager: ReactInstanceManager</span><br><span class="line"></span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">onCreate</span><span class="params">(savedInstanceState: <span class="type">Bundle</span>?)</span></span> &#123;</span><br><span class="line">        <span class="keyword">super</span>.onCreate(savedInstanceState)</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 初始化 RN 的 so 库</span></span><br><span class="line">        SoLoader.<span class="keyword">init</span>(requireContext(), <span class="literal">false</span>)</span><br><span class="line"></span><br><span class="line">        rootView = ReactRootView(requireContext())</span><br><span class="line">        reactInstanceManager = ReactInstanceManager.builder()</span><br><span class="line">            <span class="comment">// 传入 Application 实例</span></span><br><span class="line">            .setApplication(globalApp)</span><br><span class="line">            .setCurrentActivity(requireActivity())</span><br><span class="line">            <span class="comment">// 传入 asset 文件中 RN bundle 的文件名，也可以传入本地文件</span></span><br><span class="line">            .setBundleAssetName(<span class="string">&quot;index.android.bundle&quot;</span>)</span><br><span class="line">            .setUseDeveloperSupport(<span class="literal">false</span>)</span><br><span class="line">            <span class="comment">// 这里可以通过传入自定义的 package 来支持 RN 原生模块和原生 View 组件</span></span><br><span class="line">            .addPackages(listOf(MainReactPackage()))</span><br><span class="line">            .setInitialLifecycleState(LifecycleState.RESUMED)</span><br><span class="line">            .setJSMainModulePath(<span class="string">&quot;index&quot;</span>)</span><br><span class="line">            .setDefaultHardwareBackBtnHandler &#123;</span><br><span class="line">                Log.d(TAG, <span class="string">&quot;onCreate: defaultHardwareBackHandler handle&quot;</span>)</span><br><span class="line">            &#125;</span><br><span class="line">            .build()</span><br><span class="line"></span><br><span class="line">        <span class="comment">// 启动 RN 应用</span></span><br><span class="line">        rootView.startReactApplication(</span><br><span class="line">            reactInstanceManager,</span><br><span class="line">            <span class="comment">// 传入 RN 中通过 AppRegistry.registerComponent() 注册的组件名</span></span><br><span class="line">            <span class="string">&quot;react_native_cli_init&quot;</span>,</span><br><span class="line">            <span class="comment">// 在这里通过 Bundle 给 RN 组件传递参数，RN 组件会通过 props 接收参数</span></span><br><span class="line">            arguments</span><br><span class="line">        )</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">onCreateView</span><span class="params">(</span></span></span><br><span class="line"><span class="params"><span class="function">        inflater: <span class="type">LayoutInflater</span>, container: <span class="type">ViewGroup</span>?, </span></span></span><br><span class="line"><span class="params"><span class="function">        savedInstanceState: <span class="type">Bundle</span>?</span></span></span><br><span class="line"><span class="params"><span class="function">    )</span></span>: View = rootView <span class="comment">// 返回创建的 ReactRootView 实例</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure><p>这样就实现了基本的 React Native 组件嵌入 Android Fragment 中。</p>]]></content:encoded>
      
      
      
      <category domain="https://blog.ikvarxt.me/tags/Android/">Android</category>
      
      <category domain="https://blog.ikvarxt.me/tags/React-Native/">React Native</category>
      
      
      <comments>https://blog.ikvarxt.me/integrate-react-native-to-android-fragment/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>HarmonyOS 鸿蒙上使用 Compose imePadding 无效的问题</title>
      <link>https://blog.ikvarxt.me/HarmonyOS-imePadding-not-working/</link>
      <guid>https://blog.ikvarxt.me/HarmonyOS-imePadding-not-working/</guid>
      <pubDate>Thu, 27 Jun 2024 09:54:53 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;先说结论：&lt;/p&gt;
&lt;p&gt;Manifest 中 Activity 的 &lt;code&gt;android:windowSoftInputMode&lt;/code&gt; 标记避免使用 &lt;code&gt;adjustNothing&lt;/code&gt;，而是使用 &lt;code&gt;adjustResize&lt;/co</description>
        
      
      
      
      <content:encoded><![CDATA[<p>先说结论：</p><p>Manifest 中 Activity 的 <code>android:windowSoftInputMode</code> 标记避免使用 <code>adjustNothing</code>，而是使用 <code>adjustResize</code> 等其他 “adjust” 值。</p><hr><p>使用 Compose 构建的登录页面在鸿蒙系统上遇到了给 Composable 组件设置 imePadding 无效的问题，在网络上没有找到相关的博客，大家都在关注使用 KMP 构建纯血鸿蒙的方案。</p><p>想到了 <a href="https://developer.android.com/develop/ui/views/touch-and-input/keyboard-input/visibility?hl=zh-cn#Respond">处理输入法可见性</a>，才发现我项目中设置的是 <code>adjustNothing</code>，改成 <code>adjustResize</code> 就可以了。</p>]]></content:encoded>
      
      
      
      <category domain="https://blog.ikvarxt.me/tags/Android/">Android</category>
      
      <category domain="https://blog.ikvarxt.me/tags/Compose/">Compose</category>
      
      
      <comments>https://blog.ikvarxt.me/HarmonyOS-imePadding-not-working/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>About me</title>
      <link>https://blog.ikvarxt.me/2024/06/21/about/me/</link>
      <guid>https://blog.ikvarxt.me/2024/06/21/about/me/</guid>
      <pubDate>Fri, 21 Jun 2024 13:05:57 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;This is the Ikvarxt’s blog, sharing everything about my life and Android.&lt;/p&gt;
</description>
        
      
      
      
      <content:encoded><![CDATA[<p>This is the Ikvarxt’s blog, sharing everything about my life and Android.</p>]]></content:encoded>
      
      
      
      
      <comments>https://blog.ikvarxt.me/2024/06/21/about/me/#disqus_thread</comments>
      
    </item>
    
    <item>
      <title>Hello World</title>
      <link>https://blog.ikvarxt.me/2024/06/20/hello-world/</link>
      <guid>https://blog.ikvarxt.me/2024/06/20/hello-world/</guid>
      <pubDate>Thu, 20 Jun 2024 00:00:00 GMT</pubDate>
      
        
        
      <description>&lt;p&gt;Welcome to &lt;a href=&quot;https://hexo.io/&quot;&gt;Hexo&lt;/a&gt;! This is your very first post. Check &lt;a href=&quot;https://hexo.io/docs/&quot;&gt;documentation&lt;/a&gt; for</description>
        
      
      
      
      <content:encoded><![CDATA[<p>Welcome to <a href="https://hexo.io/">Hexo</a>! This is your very first post. Check <a href="https://hexo.io/docs/">documentation</a> for more info. If you get any problems when using Hexo, you can find the answer in <a href="https://hexo.io/docs/troubleshooting.html">troubleshooting</a> or you can ask me on <a href="https://github.com/hexojs/hexo/issues">GitHub</a>.</p><h2 id="Quick-Start"><a href="#Quick-Start" class="headerlink" title="Quick Start"></a>Quick Start</h2><h3 id="Create-a-new-post"><a href="#Create-a-new-post" class="headerlink" title="Create a new post"></a>Create a new post</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo new <span class="string">&quot;My New Post&quot;</span></span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/writing.html">Writing</a></p><h3 id="Run-server"><a href="#Run-server" class="headerlink" title="Run server"></a>Run server</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo server</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/server.html">Server</a></p><h3 id="Generate-static-files"><a href="#Generate-static-files" class="headerlink" title="Generate static files"></a>Generate static files</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo generate</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/generating.html">Generating</a></p><h3 id="Deploy-to-remote-sites"><a href="#Deploy-to-remote-sites" class="headerlink" title="Deploy to remote sites"></a>Deploy to remote sites</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">$ hexo deploy</span><br></pre></td></tr></table></figure><p>More info: <a href="https://hexo.io/docs/one-command-deployment.html">Deployment</a></p>]]></content:encoded>
      
      
      
      
      <comments>https://blog.ikvarxt.me/2024/06/20/hello-world/#disqus_thread</comments>
      
    </item>
    
  </channel>
</rss>
