[Android] 복사할 수 없는 텍스트 복사

Android에서 선택할 수 없음( textIsSelectable =false) 텍스트를 복사하는 방법.
스쿠쇼라고 다루기 힘들고 장문이라면 지옥이므로, 찾아낸 방법을 메모해 둔다.

결론에서 말하면, uiautomator dump 커멘드로 표시하고 있는 텍스트의 전문을 취득할 수 있다.
비록 선택할 수 있는 경우라도 PC에서 고뇨고 싶은 경우는 "선택"→ "공유"보다 편리.
확인은 Android10에서 실시하였다.



이 상태에서 uiautomator dump 명령을 실시한 결과가 이하 (보기 쉽도록 xmllint 로 정형하고 있다).resource-id="xyz.takeoverjp.jugemuviewer:id/jugemView"text 의 내용이, 목적의 캐릭터 라인이 되어 있는 것을 알 수 있다.
$ adb shell uiautomator dump
UI hierchary dumped to: /sdcard/window_dump.xml
$ adb shell cat /sdcard/window_dump.xml | xmllint --format -
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<hierarchy rotation="0">
  <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,2040]">
    <node index="0" text="" resource-id="" class="android.widget.LinearLayout" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,2040]">
      <node index="0" text="" resource-id="" class="android.widget.FrameLayout" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,60][1080,2040]">
        <node index="0" text="" resource-id="xyz.takeoverjp.jugemuviewer:id/decor_content_parent" class="android.view.ViewGroup" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,60][1080,2040]">
          <node index="0" text="" resource-id="xyz.takeoverjp.jugemuviewer:id/action_bar_container" class="android.widget.FrameLayout" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,60][1080,200]">
            <node index="0" text="" resource-id="xyz.takeoverjp.jugemuviewer:id/action_bar" class="android.view.ViewGroup" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,60][1080,200]">
              <node index="0" text="JugemuViewer" resource-id="" class="android.widget.TextView" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[40,96][377,163]"/>
            </node>
          </node>
          <node index="1" text="" resource-id="android:id/content" class="android.widget.FrameLayout" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,200][1080,2040]">
            <node index="0" text="" resource-id="" class="android.view.ViewGroup" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,200][1080,2040]">
              <node index="0" text="" resource-id="" class="android.widget.ScrollView" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="true" focused="false" scrollable="true" long-clickable="false" password="false" selected="false" bounds="[29,200][1052,2040]">
                <node index="0" text="寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助寿限無、寿限無、 五劫の擦り切れ、 海砂利水魚の、 水行末・雲来末・風来末、 喰う寝る処に住む処、 藪ら柑子の藪柑子、 パイポ・パイポ・パイポのシューリンガン、 シューリンガンのグーリンダイ、 グーリンダイのポンポコピーのポンポコナーの、 長久命の長助" resource-id="xyz.takeoverjp.jugemuviewer:id/jugemView" class="android.widget.TextView" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[29,200][1052,2040]"/>
              </node>
            </node>
          </node>
        </node>
      </node>
    </node>
    <node index="1" text="" resource-id="android:id/statusBarBackground" class="android.view.View" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][1080,60]"/>
    <node index="2" text="" resource-id="android:id/navigationBarBackground" class="android.view.View" package="xyz.takeoverjp.jugemuviewer" content-desc="" checkable="false" checked="false" clickable="false" enabled="true" focusable="false" focused="false" scrollable="false" long-clickable="false" password="false" selected="false" bounds="[0,0][0,0]"/>
  </node>
</hierarchy>
uiautomator 명령은 UI를 포함한 자동 테스트를 위한 프레임워크의 일부입니다.
테스트 작성시의 레이아웃 조사용으로 dump 기능을 가지고 있기 때문에, 이용했다.

또한 Android Studio와 함께 제공되는 Layout Inspector와 Android SDK와 함께 제공되는 uiautomatorviewer를 사용해도 마찬가지입니다.
GUI를 좋아하는 경우나, node와 표시와의 관계를 잘 모르는 경우는 이것들을 사용하면 좋다.TextViewmText 를 선택하고 Ctrl+C 하면 복사 가능.
  • Layout Inspector


  • uiautomatorviewer



  • 참고



    Test UI for multiple apps - Android Developer
    Layout Inspector - Android Developer
    TextView#textIsSelectable - Android Developer
    UiAutomator 정보 - Qiita
    수한무 - Wikipedia

    좋은 웹페이지 즐겨찾기