[
  {
    "path": ".gitattributes",
    "content": "* text=auto\n*.sh text eol=lf\nhooks/* text eol=lf\n\n*.png binary\n*.ico binary\n*.woff binary\n*.woff2 binary"
  },
  {
    "path": ".github/dependabot.yml",
    "content": "version: 2\nupdates:\n\n  # Maintain dependencies for GitHub Actions\n  - package-ecosystem: \"github-actions\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n\n  # Maintain dependencies for npm\n  - package-ecosystem: \"npm\"\n    directory: \"/\"\n    schedule:\n      interval: \"daily\"\n"
  },
  {
    "path": ".gitignore",
    "content": "/.vscode\n/node_modules\n/yarn.lock\n"
  },
  {
    "path": "appops/.gitignore",
    "content": "/.vuepress/dist"
  },
  {
    "path": "appops/.vuepress/config.js",
    "content": "const moment = require('moment')\nconst langMap = {\n  \"zh-Hans\": \"zh-cn\",\n  \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}\n\nmodule.exports = {\n  base: '/',\n  title: 'App Ops',\n  head: [\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]\n  ],\n  locales: {\n    '/': {\n      lang: 'en',\n      description: 'Control the hidden appops conveniently'\n    },\n    '/zh-hans/': {\n      lang: 'zh-Hans',\n      description: '方便地控制隐藏的 appops'\n    },\n    '/zh-hant/': {\n      lang: 'zh-Hant',\n      description: '方便地控制隱藏的 appops'\n    }\n  },\n  themeConfig: {\n    locales: {\n      '/': {\n        selectText: 'Languages',\n        label: 'English',\n        serviceWorker: {\n          updatePopup: {\n            message: \"New content is available.\",\n            buttonText: \"Refresh\"\n          }\n        },\n        sidebar: getSidebar(\"/guide/\", \"Basic\", \"Working modes\", \"FAQ\", \"Technical details\"),\n        nav: getNavbar('/', 'Guide', 'Download', 'Changelog', 'Rikka Apps'),\n        lastUpdated: 'Last Updated'\n      },\n      '/zh-hans/': {\n        selectText: '语言',\n        label: '简体中文',\n        editLinkText: '在 GitHub 上编辑此页',\n        serviceWorker: {\n          updatePopup: {\n            message: \"发现新内容可用.\",\n            buttonText: \"刷新\"\n          }\n        },\n        sidebar: getSidebar(\"/zh-hans/guide/\", \"基础\", \"工作模式\", \"FAQ\", \"技术细节\"),\n        nav: getNavbar('/zh-hans/', '指南', '下载', 'Changelog', 'Rikka Apps'),\n        lastUpdated: '最后更新'\n      },\n      '/zh-hant/': {\n        selectText: '語言',\n        label: '繁體中文',\n        editLinkText: '在 GitHub 上編輯此頁',\n        serviceWorker: {\n          updatePopup: {\n            message: \"發現新內容可用.\",\n            buttonText: \"重新整理\"\n          }\n        },\n        sidebar: getSidebar(\"/zh-hant/guide/\", \"基礎\", \"工作模式\", \"FAQ\", \"技術細節\"),\n        nav: getNavbar('/zh-hant/', '指南', '下載', 'Changelog', 'Rikka Apps'),\n        lastUpdated: '最後更新'\n      }\n    },\n    displayAllHeaders: true,\n    sidebarDepth: 2,\n    serviceWorker: {\n      updatePopup: true\n    },\n    docsRepo: 'https://github.com/RikkaApps/websites',\n    docsDir: 'appops',\n    editLinks: true\n  },\n  plugins: [\n    [\n      'sitemap',\n      {\n        hostname: 'https://appops.rikka.app',\n        exclude: ['/404.html'],\n        dateFormatter: (time) => {\n          timestampCache[time]\n        }\n      }\n    ],\n    /*[\n      'redirect',\n      {\n        locales: true,\n      }\n    ],*/\n    [\n      'clean-urls',\n      {\n        normalSuffix: '/',\n        indexSuffix: '/',\n        notFoundPath: '/404.html'\n      }\n    ],\n    [\n      '@vuepress/last-updated',\n      {\n        transformer: (timestamp, lang) => {\n          var original = timestamp\n\n          moment.locale(langMap[lang])\n          var localized = moment(original).format('lll')\n          \n          moment.locale('en')\n          var iso = moment(original).toISOString()\n          timestampCache[localized] = iso\n\n          return localized\n        }\n      }\n    ]\n  ]\n}\n\nfunction getSidebar(prefix, basicTitle, workingModeTitle, faqTitle, technicalDetailsTitle) {\n  var res = {}\n  res[prefix] = [\n    {\n      title: basicTitle,\n      collapsable: false,\n      sidebarDepth: 1,\n      children: [\n        ''\n      ]\n    },\n    {\n      title: workingModeTitle,\n      collapsable: false,\n      sidebarDepth: 1,\n      children: [\n        'working_mode/shizuku',\n        'working_mode/dpm',\n      ]\n    },\n    {\n      title: faqTitle,\n      collapsable: false,\n      sidebarDepth: 0,\n      children: [\n        'faq/how_to_reset',\n        'faq/purchase',\n      ]\n    },\n    {\n      title: technicalDetailsTitle,\n      collapsable: false,\n      sidebarDepth: 0,\n      children: [\n        'technical/system_behaviors',\n        'technical/run_in_background',\n      ]\n    }\n  ]\n  return res\n}\n\nfunction getNavbar(prefix, guide, download, changelog, allRikkaApps) {\n  return [\n    { text: guide, link: `${prefix}guide/` },\n    { text: download, link: `${prefix}download/` },\n    { text: changelog, link: `${prefix}changelog/` },\n    { text: allRikkaApps, link: `https://rikka.app${prefix}` },\n  ]\n}"
  },
  {
    "path": "appops/.vuepress/public/icon/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><square150x150logo src=\"/ms-icon-150x150.png\"/><square310x310logo src=\"/ms-icon-310x310.png\"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>"
  },
  {
    "path": "appops/.vuepress/public/icon/manifest.json",
    "content": "{\n \"name\": \"App\",\n \"icons\": [\n  {\n   \"src\": \"\\/android-icon-36x36.png\",\n   \"sizes\": \"36x36\",\n   \"type\": \"image\\/png\",\n   \"density\": \"0.75\"\n  },\n  {\n   \"src\": \"\\/android-icon-48x48.png\",\n   \"sizes\": \"48x48\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-72x72.png\",\n   \"sizes\": \"72x72\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.5\"\n  },\n  {\n   \"src\": \"\\/android-icon-96x96.png\",\n   \"sizes\": \"96x96\",\n   \"type\": \"image\\/png\",\n   \"density\": \"2.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-144x144.png\",\n   \"sizes\": \"144x144\",\n   \"type\": \"image\\/png\",\n   \"density\": \"3.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-192x192.png\",\n   \"sizes\": \"192x192\",\n   \"type\": \"image\\/png\",\n   \"density\": \"4.0\"\n  }\n ]\n}"
  },
  {
    "path": "appops/.vuepress/theme/components/Home.vue",
    "content": "<template>\n  <main class=\"home\" aria-labelledby=\"main-title\">\n    <header class=\"hero\">\n      <img\n        v-if=\"data.heroImage\"\n        :src=\"$withBase(data.heroImage)\"\n        :alt=\"data.heroAlt || 'hero'\"\n      >\n\n      <h1 v-if=\"data.heroText !== null\" id=\"main-title\">{{ data.heroText || $title || 'Hello' }}</h1>\n\n      <p class=\"description\">\n        {{ data.tagline || $description || 'Welcome to your VuePress site' }}\n      </p>\n\n\t  <div class=\"actions\">\n\t    <div\n          class=\"action\"\n          v-if=\"data.secondaryActionText && data.secondaryActionLink\"\n        >\n          <NavLink\n            class=\"action-button secondary\"\n            :item=\"secondaryActionLink\"\n          />\n        </div>\n\t    \n\t    <div\n          class=\"action\"\n          v-if=\"data.actionText && data.actionLink\"\n        >\n          <NavLink\n            class=\"action-button\"\n            :item=\"actionLink\"\n          />\n        </div>\n\t  </div>\n    </header>\n\n    <div\n      class=\"features\"\n      v-if=\"data.features && data.features.length\"\n    >\n      <div\n        class=\"feature\"\n        v-for=\"(feature, index) in data.features\"\n        :key=\"index\"\n      >\n        <h2>{{ feature.title }}</h2>\n        <p>{{ feature.details }}</p>\n      </div>\n    </div>\n\n    <Content class=\"theme-default-content custom\"/>\n\n    <div\n      class=\"footer\"\n      v-if=\"data.footer\"\n    >\n      {{ data.footer }}\n    </div>\n  </main>\n</template>\n\n<script>\nimport NavLink from '@parent-theme/components/NavLink.vue'\n\nexport default {\n  components: { NavLink },\n\n  computed: {\n    data () {\n      return this.$page.frontmatter\n    },\n\n    actionLink () {\n      return {\n        link: this.data.actionLink,\n        text: this.data.actionText\n      }\n    },\n\t\n\tsecondaryActionLink () {\n      return {\n        link: this.data.secondaryActionLink,\n        text: this.data.secondaryActionText\n      }\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.home\n  padding $navbarHeight 2rem 0\n  max-width 960px\n  margin 0px auto\n  display block\n  .hero\n    text-align center\n    img\n      max-width: 100%\n      max-height 280px\n      display block\n      margin 3rem auto 1.5rem\n    h1\n      font-size 3rem\n\t h1, .description, .actions\n      margin 1.8rem auto\n    .description\n      max-width 35rem\n      font-size 1.6rem\n      line-height 1.3\n      color lighten($textColor, 40%)\n\t.action\n\t  margin 0.6rem\n\t.actions\n      display flex\n      flex-wrap wrap\n      align-items flex-start\n      align-content stretch\n      justify-content center\n    .action-button\n      display inline-block\n      font-size 1.2rem\n      color #fff\n      background-color $accentColor\n      padding 0.8rem 1.6rem\n      border-radius 4px\n      transition background-color .1s ease\n      box-sizing border-box\n      border-bottom 1px solid darken($accentColor, 10%)\n      &:hover\n        background-color lighten($accentColor, 10%)\n\t  .secondary\n        color $textColor\n        background-color #fff\n        transition background-color .1s ease\n        border 1px solid darken($textColor, 10%)\n        &:hover\n          background-color lighten($textColor, 90%)\n  .features\n    border-top 1px solid $borderColor\n    padding 1.2rem 0\n    margin-top 2.5rem\n    display flex\n    flex-wrap wrap\n    align-items flex-start\n    align-content stretch\n    justify-content space-between\n  .feature\n    flex-grow 1\n    flex-basis 30%\n    max-width 30%\n    h2\n      font-size 1.4rem\n      font-weight 500\n      border-bottom none\n      padding-bottom 0\n      color lighten($textColor, 10%)\n    p\n      color lighten($textColor, 25%)\n  .footer\n    padding 2.5rem\n    border-top 1px solid $borderColor\n    text-align center\n    color lighten($textColor, 25%)\n\n@media (max-width: $MQMobile)\n  .home\n    .features\n      flex-direction column\n    .feature\n      max-width 100%\n      padding 0 2.5rem\n\n@media (max-width: $MQMobileNarrow)\n  .home\n    padding-left 1.5rem\n    padding-right 1.5rem\n    .hero\n      img\n        max-height 210px\n        margin 2rem auto 1.2rem\n      h1\n        font-size 2rem\n      h1, .description, .actions\n        margin 1.2rem auto\n      .description\n        font-size 1.2rem\n      .action-button\n        font-size 1rem\n        padding 0.6rem 1.2rem\n    .feature\n      h2\n        font-size 1.25rem\n</style>\n"
  },
  {
    "path": "appops/.vuepress/theme/components/SidebarLink.vue",
    "content": "<script>\nimport { isActive, hashRE, groupHeaders } from '@parent-theme/util'\n\nexport default {\n  functional: true,\n\n  props: ['item', 'sidebarDepth'],\n\n  render (h,\n    {\n      parent: {\n        $page,\n        $site,\n        $route,\n        $themeConfig,\n        $themeLocaleConfig\n      },\n      props: {\n        item,\n        sidebarDepth\n      }\n    }) {\n    // use custom active class matching logic\n    // due to edge case of paths ending with / + hash\n    const selfActive = isActive($route, item.path)\n    // for sidebar: auto pages, a hash link should be active if one of its child\n    // matches\n    const active = item.type === 'auto'\n      ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))\n      : selfActive\n    const link = item.type === 'external'\n      ? renderExternal(h, item.path, item.title || item.path)\n      : renderLink(h, item.path, item.title || item.path, active)\n\n    const maxDepth = [\n      $page.frontmatter.sidebarDepth,\n      sidebarDepth,\n      $themeLocaleConfig.sidebarDepth,\n      $themeConfig.sidebarDepth,\n      1\n    ].find(depth => depth !== undefined);\n\n    const displayAllHeaders = $themeLocaleConfig.displayAllHeaders\n      || $themeConfig.displayAllHeaders\n\n    if (item.type === 'auto') {\n      return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]\n    } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {\n      const children = groupHeaders(item.headers)\n      return [link, renderChildren(h, children, item.path, $route, maxDepth)]\n    } else {\n      return link\n    }\n  }\n}\n\nfunction renderLink (h, to, text, active) {\n  return h('router-link', {\n    props: {\n      to,\n      activeClass: '',\n      exactActiveClass: ''\n    },\n    class: {\n      active,\n      'sidebar-link': true\n    }\n  }, text)\n}\n\nfunction renderChildren (h, children, path, route, maxDepth, depth = 1) {\n  if (!children || depth > maxDepth) return null\n  return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {\n    const active = isActive(route, path + '#' + c.slug)\n    return h('li', { class: 'sidebar-sub-header' }, [\n      renderLink(h, path + '#' + c.slug, c.title, active),\n      renderChildren(h, c.children, path, route, maxDepth, depth + 1)\n    ])\n  }))\n}\n\nfunction renderExternal (h, to, text) {\n  return h('a', {\n    attrs: {\n      href: to,\n      target: '_blank',\n      rel: 'noopener noreferrer'\n    },\n    class: {\n      'sidebar-link': true\n    }\n  }, [text, h('OutboundLink')])\n}\n</script>\n\n<style lang=\"stylus\">\n.sidebar .sidebar-sub-headers\n  padding-left 1rem\n  font-size 0.95em\n\na.sidebar-link\n  font-size 1em\n  font-weight 400\n  display inline-block\n  color $textColor\n  border-left 0.25rem solid transparent\n  padding 0.35rem 1rem 0.35rem 1.25rem\n  line-height 1.4\n  width: 100%\n  box-sizing: border-box\n  &:hover\n    color $accentColor\n  &.active\n    font-weight 600\n    color $accentColor\n    border-left-color $accentColor\n  .sidebar-group &\n    padding-left 2rem\n  .sidebar-sub-headers &\n    padding-top 0.25rem\n    padding-bottom 0.25rem\n    border-left none\n    &.active\n      font-weight 500\n</style>\n"
  },
  {
    "path": "appops/.vuepress/theme/index.js",
    "content": "module.exports = {\n  extend: '@vuepress/theme-default'\n}"
  },
  {
    "path": "appops/.vuepress/theme/layouts/Layout.vue",
    "content": "<template>\n  <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport default {\n  components: {\n    ParentLayout\n  }\n}\n</script>"
  },
  {
    "path": "appops/.vuepress/theme/styles/index.styl",
    "content": "code\n  overflow: auto\n  word-wrap:break-word\n\nbody\n  font-family Roboto, sans-serif\n\nbody:lang(zh-hans)\n  font-family Roboto, 'Noto Sans SC', sans-serif\n\nbody:lang(zh-hant)\n  font-family Roboto, 'Noto Sans TC', sans-serif\n"
  },
  {
    "path": "appops/.vuepress/theme/styles/palette.styl",
    "content": "$accentColor = #1565c0\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
  },
  {
    "path": "appops/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Download\nactionLink: /download.html\nsecondaryActionText: Learn more\nsecondaryActionLink: /guide/\nfeatures:\n- title: Access hidden permission mechanism\n  details: Control permissions (partial) by modifying hidden appops settings with App Ops.\n- title: Excellent user experience\n  details: Provides a beautiful and friendly user interface. App Ops does a lot of effort in many places to reduce the difficulty of use.\n- title: Works without root\n  details: Provides a variety of working modes that only require adb.\n- title: Follow the latest Android system\n  details: Support features from newer Android version, even the beta version will be supported in a few days.\n- title: Detailed help\n  details: Provide detailed help documents.\n- title: Provides advanced features\n  details: Easy to use with features such as templates, backup and recover.\nfooter: Copyright © 2019 RikkaApps\n---"
  },
  {
    "path": "appops/changelog.md",
    "content": "# Changelog\n\n## 9.0.6 (2023-08-03)\n\n- Upgrade Shizuku to 13.5.0+ could solve the problem that automatic functions not work\n- Fix the problem of \"Unable to start service\" on some realme devices\n- Fix crash on pre-Android 7.1\n\n## 9.0.0 (2023-04-08)\n\n- Add \"Sensors\" permission for Android 10 and above, which can control whether the app can use accelerometer, gravity sensor and other sensors that can be used without permission\n- Support for Android 14 (however, based on experience, the app will most likely not work again due to later changes)\n- Hide `OP_TOAST_WINDOW` on Android 11+ for apps targeting API 30+ as it no longer works\n- Add instructions for storage permissions on Android 10+, the system allows eligible apps to write to standard folders even if they do not have storage permissions (eligible apps are apps that target API 30 or above, or target API 29 and have adapted Scoped Storage)\n- Added option to allow backup of system components\n- For Chinese, Japanese and Korean language users, if the system does not provide a Medium (500) weight font, it will use the simulation implementation\n- Added prompt information for `com.android.externalstorage`, `com.android.providers.downloads`, `com.samsung.android.providers.media` not having permissions on Samsung devices\n\n## 8.0.1 (2022-11-22)\n\n- Allow backup without purchasing (restore the backup still need purchasing)\n- Fix swithing user not working randomly\n\n## 8.0.0 (2022-09-02)\n\n- Experimental feature for Android 12 +: Usage history\n- Adapt Android 12 to changes in location permissions\n- Material Design 3\n- Device admin mode removed due to Google Play policy changes\n\n## 5.5.6 (2022-06-10)\n\n- Works on Android 13 Beta 3\n- Fix crash under French language\n- Device Admin mode will be removed due to new Google Play policy changes\n\n## 5.5.2 (2022-03-10)\n\n- Replace the app icon because the old one \"violates Google Play policies\"\n\n## 5.5.0 (2022-03-03)\n\n- Works on Android 13 DP1 (however, based on experience, DP1 is a very early version and the app will most likely not work again due to changes in DP2)\n\n## 5.4.3 (2021-06-13)\n\n- Fix the problem that \"Automatic recovery\" could cause all permissions in the same group be reset to \"Ignore\"\n\n## 5.4.2 (2021-06-01)\n\n- Fix backup is broken from version 5.4.0\n- Fix some visual problem on old systems\n\n## 5.4.0 (2021-05-27)\n\n- Fix Clipboard monitor does not work on Android 12 Beta 1\n- Fix \"Ignore\" cannot be set for apps in work profiles on Android 11+ (This fix is only possible under Shizuku mode)\n- Hide `OP_QUERY_ALL_PACKAGES` since this op does nothing\n- Hide `OP_NO_ISOLATED_STORAGE` since this op is only for debugging use\n\n## 5.3.3 (2021-05-04)\n\n- Adapt another Android 12 changes\n- Prevent 💩 MIUI's \"Force dark mode\" from breaking app's theme<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI has its own \"Force dark mode\". However, it seems that even if the app has provided the correct dark theme, MIUI's \"Force dark mode\" will still take effect and finally mess up colors.</sub>\n\n## 5.3.1 (2021-04-03)\n\n- Fix a problem that would cause the crash\n- Adapt some Android 12 changes\n\n## 5.3.0 (2021-01-28)\n\n- The first step of correctly handling Shared user ID\n\n## 5.2.0 (2021-01-16)\n\n- Support Sui (https://github.com/RikkaApps/Sui)\n\n## 5.1.3 (2020-11-29)\n\n- Adapt changes of \"Storage Isolation\" v5\n- Fix a problem that the backup will be broken if the system returns \"wrong\" data (exiting broken backups cannot be fixed)\n\n## 5.1.2 (2020-10-07)\n\n- Fix a problem related to creating backup\n- Fix a problem related to \"Clipboard monitor\"\n- Fix the problem that records for \"Automatic recovery\" sometimes may not be updated correctly\n- Import translation from users\n\n## 5.1.0 (2020-09-24)\n\n- All options are now available for batch operations of \"App detail\" and \"Permissions view\" (note that when multiple items are selected, the displayed options are the intersection of all available options)\n- Add search for \"Permissions view\"\n\n## 5.0.6 (2020-09-06)\n\n- Fix a problem related to creating backup\n- Fix a problem related to batch operations (including using templates, backups, etc.)\n- Import translation from users\n- Other minor changes\n\n## 5.0.4 (2020-08-30)\n\n- Fix the problem that \"Restoring backup\" may be displayed when nothing is actually restored\n- Import translation from users\n- Other minor changes\n\n## 5.0.3 (2020-08-27)\n\n- Fix problem introduced in 5.0.2 (1236)\n\n## 5.0.2 (2020-08-26)\n\n- \"Automatic recovery\" option is enforced for all Android 10 as it is confirmed that Android 10 also do the reset (only in fewer cases than Android 11)\n- Fix the problem that, under Delegated Device Admin mode, things available from Island 5.0+ is accidentally requested on all versions\n- Fix the problem that the ignore option of \"Automatic recovery\" not actually works\n- Fix the problem that, `RUN_IN_BACKGROUND` in the template is not correctly displayed after editing\n\n## 5.0.1 (2020-08-24)\n\n- Fix the problem that in the last version, admin apps using DSM API v3 are incorrectly marked as \"missing support\"\n- Fix the problem that in the last version, not all options are displayed correctly in \"Template\"\n- Fix the problem that in the last version, automatic backup restore function for frozen applications (based on \"hide\") is broken\n- Reset package mode when necessary (for \"incorrect\" settings leaved by older App Ops or other appops tools that haven't adapt system changes correctly)\n- Import user translations\n\n## 5.0.0 (2020-08-22)\n\nThis update fixes a hidden but long-standing problem. Because the problem rarely occurs in low version system, and the existing settings are not affected after upgrading to Android, this problem was surfaced recently. A typical example is, in Android 10, once you have changed location permission from the system, changes in older versions of App Ops will never work (even if it seems to be changed successfully).\n\nThis contains a lot of work behind, please read [technical details](./guide/technical/system_behaviors/).\n\n**What you should to know:**\n\n- What you see or change in App Ops now reflects the final status\n- \"Deny\" in older versions is renamed to \"Ignore\"\n- Old backups are no longer supported because they lack the necessary information (they may even contain wrong information)\n- For Delegated Device Admin mode, currently, only Island v5.0+ has the support of new required APIs\n- For Delegated Device Admin mode, part of the backup is from historical user actions, this is because admin apps does not have enough permission to get the accurate status (this is system limitation)\n\nOther changes:\n\n- Template: any options can be used in the template\n- Backup: more flexibility when restoring\n- Usage monitor: attempt to reduce \"wrong\" reports (sometimes the systems always reports app is using \"location\" even if the app is not running)\n- Usage monitor & Clipboard monitor: add \"exclude system apps\" option\n\n## 4.2.3 (2020-07-18)\n\n- Add Turkish translation\n- \"Usage monitor\" fix\n\n## 4.2.2 (2020-07-16)\n\n- Solved the problem of small probability of random stop from v4.0.0\n- \"Usage monitor\" improvements\n- Rearrange strings, anyone can participate in translation\n\n## 4.2.0 (2020-07-12)\n\n- Add \"Usage monitor\" (Requires Android 9+ & Shizuku starts via root)\n\n  Get notified when apps are using location, camera or microphone\n\n## 4.1.1 (2020-07-10)\n\n- Clipboard monitor: temporary access time is now optionable\n- Clipboard monitor: fix a UI issue of \"Excluded apps\"\n- Fix the problem that on Android 10+, the backup created after v4.0.0 may be broken\n- Correctly report the error from DPM mode\n- Temporarily not to use resource optimization feature from AAPT2, maybe this could solve the problem of random settings crash happens on some users\n\n## 4.1.0 (2020-07-09)\n\n- Clipboard monitor: add \"Window position\" and \"Excluded apps\" option\n- Fix the problem that once the main process is dead, \"New app behavior\" will stop working\n- Fix the problem for permission view, ui is not refreshed correctly\n\n## 4.0.1 (2020-07-05)\n\n- Fix the problem that in some situations, the monitor service is started abnormally\n\n## 4.0.0 (2020-07-04)\n\nRewrite (partly) the app with latest technologies. The full rewrite with more improvements and new features will come in the near future.\n\n- New feature: Clipboard monitor (Requires Android 10+ and Shizuku started with root)<sup>**〔1〕**</sup>\n- Works on Android 10 & 11\n- UI refresh\n- Fix a problem related to restoring backup\n- Always use built-in names<sup>**〔2〕**</sup>\n- For free version, remove Google Ads (Promote our apps instead)\n- For crash report, use AppCenter to replace Firebase Crashlytics (Also, crash report can be disabled)\n- Target API 30\n- Drop support for system plugin mode\n- Drop support for Android 6.0\n- Drop support for ask mode from old LineageOS based ROMs<sup>**〔3〕**</sup>\n\n<sub><b>〔1〕</b>Exclude apps from the monitor will come in the next version</sub>\n<br><sub><b>〔2〕</b>Previously, the name of \"the permission\" is used in priority. But as Android changes some permission name across versions, the name is more and more inaccurate.</sub>\n<br><sub><b>〔3〕</b>Due to user reports, some old Samsung devices \"appear to have this feature\", but change to \"ask\" will cause the system unable to boot.</sub>\n\n## 3.1.1 (2019-08-03)\n\n- Fix can't modify template\n\n## 3.1.0 (2019-08-02)\n\n- Provide more obvious warnings when doing operations on system apps\n- Provide edit & add for apply template dialog\n- Fix the problem that it will always determine that you are using Island once you have used Island in Delegated Device admin mode\n\n## 3.0.3 (2019-07-29)\n\n- Minor bug fix\n- Provide new website with document: <https://appops.rikka.app/>\n\n## 3.0.2\n\n- Fix Delegated Device admin is broken\n- Fix wrong dependency\n\n## 3.0.0\n\n- Delegated Device admin mode: Fix app installation may not triggered when using Island\n- (Experimental) Delegated Device admin mode: Support multi-user (Requires Island 3.8+ as Device admin. For 2019/7/24, it's available in Google Play alpha channel)\n- Template: check \"Skip check\" for default\n- Template: improve edit UI\n- Show prompt if an op is not included in stock Android\n- Other bug fixes & UI improve\n\n## 2.9.9\n\n- Delegated Device admin mode: Fix some bugs related to Island support\n- Privilege mode: Fix legacy Shizuku is always required\n- Show all working modes (explains the reason if not support)\n\n## 2.9.8\n\n- (Experimental) Delegated Device admin mode support \"God mode\" of Island app (com.oasisfeng.island)\n- Privilege mode: Fix \"adb permission limited\" prompt never shows (mainly for MIUI)\n\n## 2.9.7\n\n- Try to fix \"Code 5\"\n\n## 2.9.5\n\n- Bring back access/reject time for Android Q beta 4 (but as Android Q changed data format and not open sourced yet, no detailed times like Android 9)\n- Fix \"Code 5 debug message: null\" (by upgrading lib from Google :(\n- Minor UI tweaks\n\n## 2.9.4\n\n- Target 29\n- Fix bugs in 2.9.2\n\n## 2.9.2\n\n- Fix template is lost after upgrading to 2.9.1\n- Notification language should follow app language setting perfectly\n\n## 2.9.1\n\n- Add Delegated Device admin mode (use API from supported Device admin app)\n- Fix some bugs\n- Include templates to backup\n\n## 2.8.2\n\n- Fix root mode not work on Android Q beta 3\n- Fix a few features on older versions of Android may not work properly\n- Fix \"Show framework apps\" option not work under root mode\n- Fix overlay packages are not filtered under root mode\n\n## 2.8.1\n\n- Works on Android Q beta 3 (unable to see usage time now)\n- Storage options not work on Q beta 3, it's a system bug\n- Temporarily hide \"Storage sandbox\" option for Q beta AlipayPaymentDialogFragment3 (disable by default unless app declared, how to force enable is not clear)\n- Update translation\n- Set first template as default when not set (to save user who never read prompt text)\n\n## 2.8.0\n\n- Support new ops added from Android Q\n- UI improve\n\n## 2.7.0\n\n- No more \"Restart app required\" on Android 9\n- No more random error when use privilege mode (require upgrade to Shizuku v3 and force stop App Ops)\n\n## 2.6.4\n\n- Update translation\n- Bug fix\n\n## 2.6.3\n\n- Update translation\n- Bug fix\n\n## 2.6.2\n\n- Multi-user support for root mode (experimental)\n- Add \"Disabled first\" for grouping by permissions list\n- Improved \"run in background\" control UI for Android 9\n- Bug fix\n\n## 2.5.10\n\n- Add help for Android 9\n- Bug fix\n\n## 2.5.9\n\n- Fix bug related to multi-user\n- Update pt-BR translation\n\n## 2.5.8\n\n- Fix bug\n\n## 2.5.7\n\n- Simplify detail UI\n- Fix some ops can't be changed if this permission related to its'\n  opToSwitch's is not requested\n\n## 2.5.5\n\n- Fix process when first time using privileged mode on not rooted Android 9\n- Fix the problem about losing unsaved data while editing template after screen rotation\n- Press back to ask whether to save when editing template\n- Fix crash when press enter in template name\n- Hide unknown ops by default\n- Update ru translation\n\n## 2.5.3\n\n- Fix bugs about new app monitor feature\n- Try to fix crash when open app on users\n\n## 2.5.2\n\n- Fix system plugin mode is broken in 2.5.0\n- Fix error information is not correctly displayed\n- Fix not work on Android 7.x\n- Fix the problem that \"You have already own this item\" happens on some Google Play users\n- To make New app monitor feature more reliable, it requires foreground service now (only Android 8.0+),\n  but you can disable notification or set it to lowest importance to avoid being disturbed\n\n## 2.5.0\n\n- Remove System plugin for Android 9+\n  (because the plugin could work only if it is signed with the system signature)\n- Simplify system plugin installation, provide zip download only\n- Support appops features added from Android 9 (such as MODE_FOREGROUND & OP_RUN_ANY_IN_BACKGROUND)\n- New UI\n- Multi templates\n- Solve the problem that unable to use if back to app after a long time\n\n## 2.4.1\n\n- Update translation\n- Try to fix the problem that some paid users may be treated as unpaid\n\n## 2.4.0\n\n- Increase the speed of root mode\n\n## 2.3.13\n\n- May fix root mode not work on some devices\n- Change icon for Android 8+\n\n## 2.3.12\n\n- Try fix crash when restore backup\n\n## 2.3.11\n\n- Add select all for all list (long press item -> 3-dot menu -> select all)\n- System plugin mode now provides Magisk module template v1500 for Magisk users\n\n## 2.3.10\n\n- Fix crash when restore large number of backups\n- Fix tip dialog content is not scrollable\n\n## 2.3.9\n\n- Fix crash on Android P DP1 (you may see the \"Detect problems with API compatibility\" toast, but it's impossible for AppOps not use hidden APIs)\n\n## 2.3.8\n\n- Add \"Show all modes\" option (do not enable it if don't know what it is)\n\n## 2.3.7\n\n- _Always-shown permission (operation)_ will exclude some impossible situation\n- Add error tip when App Ops in installed to external storage\n- Update Portuguese (Brazil) translation\n- Remove some unused resources\n- Fix create backup is broken\n\n## 2.3.6\n\n- Fix \"Google play not available\"\n- Add a list which displays all supported permissions (operation)\n- Mark system app in app list\n- Add _always-shown permission (operation)_ list, selected permissions will be treated may be used by all apps\n- Settings UI tweak\n\n## 2.3.5\n\n- Fix backup preview is broken\n- Add tip when local network (required by privileged mode) is limited\n- Handle some uncaught error\n\n## 2.3.4\n\n- Fix reset is broken in root mode\n- Fix reset or apply template from app list not refresh the UI\n\n## 2.3.3\n\n- Fix two old bug\n\n## 2.3.2\n\n- Fix bug in 2.3.0\n- Asynchronous load other information (such as modified item count), so the app list loading process should be very fast now\n\n## 2.3.0\n\n- Add modified item count for app list\n- Accelerate the process of fetching appops configuration when use root mode\n- New Oreo-styled app detail view\n- Support Android 8.1's light navigation bar\n- Modify some confusing UI\n- (Free users) Use old banner ads since Google will remove native express ads after March 2018\n- Fix some multi-user related problems\n- (Paid users) Fix a problem which related to auto backup restore\n- Remove support for old Shizuku (privileged mode) due to some reason\n\n## 2.2.6\n\n- Fix unable to use when install Shizuku Manager later than open App Ops\n\n## 2.2.5\n\n- Add start on boot for new app monitoring\n- Add Portuguese (Brazil) language\n\n## 2.2.4\n- Add a tip for the situation that adb only have get but no update appops configuration permission (most likely happened on MIUI ROM)\n- Use new version build tool to avoid ([a terrible problem](https://issuetracker.google.com/issues/64434571)) on some custom ROM\n\n## 2.2.3\n\n- Fix possible crash when use _Privileged mode_ with old _Shizuku Manager_\n- Do not check whether there is `RUN_IN_BACKGROUND` when applying template from notification\n- Fix settings crash when switch work mode\n\n## 2.2.2\n\n- Fix crash when _Privileged mode_ is selected but _Shizuku Manager_ is not installed\n\n## 2.2.1\n\n- Add a feature that can change UI language\n- Update translation\n- Filter overlay apps by reflect `PackageInfo#overlayTarget`\n- Fix action in new app notification may not work on some device\n- Do not check whether there is `RUN_IN_BACKGROUND` when applying template\n\n## 2.2.0\n\n- Fix notification can't be dismissed after apply template or restore backup\n- Reschedule main menu items\n- Move \"Show framework apps\" to main menu\n- Add \"Sort by update time\", \"Sort by installation time\"\n- Lab add \"Show target 0 apps\" (for filter substratum overlay)\n- Refactor setup wizard, also add more explanation\n- Adjust settings UI\n- Fix notification can't show adaptive icon (8.0+)\n\n## 2.1.12 (beta)\n\n- Temporarily query less data when fetching app list\n\n> This will solve the problem that only part of app list is fetched (or even \"Package Manager has died\")\non some devices.\n\n> Also makes the fetching progress faster.\n\n> But without removed data, we have to remove \"show apps without icon\" option because we can't know\nif the app have a entrance, and \"run in background\" (Android 7.0+) will always shown because we can't\nspeculated if the app have background behavior.\n\n- (Privileged mode) Let Shizuku manager show user server is not running\n- New version name rule\n- Adapt Font Provider API v8\n\n## 2.1.11\n\n- Fix system plugin broadcast does not work\n- Fix notification didn't show when plugin stopped\n- Improve Settings UI for RTL language\n- Introduce Shizuku v2 (privileged mode) for test, join test of Shizuku Manager if you want a try\n- Font Provider (medium font weight for CJK language) is enabled by default\n\n## 2.1.10\n\n- Add a more friendly tip when system plugin don't have enough permission\n- Try again to fix manual refresh is sometimes required when use system plugin\n- Update Font Provider (for CJK language users) dependency to 1.3.2\n- Add more help\n- Fix some dialog's button color\n\n## 2.1.9\n\n- Fix NPE in WorkService\n- Move system plugin download to GitHub release\n- Fix crash when open help in runtime permission tip dialog\n- Notify list refresh when system plugin connected\n- Update translation\n- Add translator's name to about\n\n## 2.1.2 - 2.1.8\n\n- Fix can't create backup file\n- The entrance of Lab (including undetermined and experimental features) is now always enabled\n- Provide fastScroll drawable from AOSP to avoid crash on some devices\n- Update help\n- Fix test link in pro version\n- 100% fix theme and night mode, it should work perfectly now\n- Update adaptive icon for Android O\n- Add tip of Runtime Permissions when entering app target 23+\n- Improved theme\n- Add an option to use \"Noto Sans CJK Medium\" font from Font Provider app to replace \"sans-serif-medium\"\n- Add tip for users can't use system plugin on Android O\n\n## 2.1.1\n\n- Enhanced backup (PRO)\n  - Once user changed permission settings, the settings will be saved to database automatically, it can be restored when the app installed again after uninstalling or re-enabled after disabled by freezer apps using DevicePolicyManager (such as [Icebox](https://play.google.com/store/apps/details?id=com.catchingnow.icebox)'s non-root mode).\n- Add detailed changelog\n- New detailed help"
  },
  {
    "path": "appops/download.md",
    "content": "# Download\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com/apk/rikka.appops)\n\n[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)\n"
  },
  {
    "path": "appops/guide/README.md",
    "content": "# Learn App Ops\n\nIn short, **App Ops** is an app that **modifies the settings of \"appops\" in Android system**.\n\n## What is \"appops\" in Android?\n\nThere is a system service called \"appops\" in the Android system that defines a series of \"application operation\" (op). Some of the \"application operations\" correspond to \"permissions\" (such as `OP_CAMERA` and \"camera permission\"), and the rest correspond to separate functions (such as `OP_READ_CLIPBOARD` and read clipboard, but there is no \"read clipboard permission\").\n\nStock Android systems use appops to track permission usage, and appops is also used in part for permission control. Each app has its own \"appops\" setting, and when the app needs to perform certain actions, the system checks the \"appops\" settings while checking permission. If permission is not granted, the app will receive an error when performing the operation. But the difference is, if \"appops\" is set to \"Ignore\" <sup>**\\[1\\]**</sup>, the app will not receive the error and will only receive blank data <sup>**\\[2\\]**</sup>.\n\nHowever, the stock Android system does not provide a user interface that modifies the \"appops\" settings.\n\n<sub>**\\[1\\]** App Ops app actually shows \"Ignore\" as \"Deny\"</sub>\n<br><sub>**\\[2\\]** The actual behavior depends on the system, and the app can also check if \"appops\" is denied</sub>\n\n## What is App Ops app?\n\nThe core function of App Ops app is to modify the system \"appops\" settings to implement permission management in a sense. App Ops app also makes a lot of effort to simplify many technical details and make it easier to use.\n\n## Term\n\n### \"Permissions\"\n\nApp Ops actually modifies \"application operation\" rather than \"permission\", but we call it \"permissions\" to reduce the difficulty. App Ops app **can't control \"permissions\" directly**, please don't misunderstand.\n\n::: tip\nWe still call it \"permission\" in the rest of the help\n:::\n\n## Limitations of App Ops\n\n### Permissions can be modified are depend on your system\n\nThe permissions that App Ops can modify **depend only on your system**, so stop asking \"why there is no XXX permission\".\n\nIn general, the higher the system version, the more permission you can modify (manufacturers or custom ROMs may add their own permission). All permissions supported by your system can be found in Settings - Behavior - All Permissions.\n\n### Apps can still check if they have no permission\n\nApps can check if the returned data is blank or directly check if \"appops\" is allowed. But there are very few apps do this."
  },
  {
    "path": "appops/guide/faq/how_to_reset.md",
    "content": "# How to reset all settings?\n\n1. Switch to app list mode\n2. Long press or tap the app icon on the left to enter multi-select mode\n3. Three-dot menu - Select all\n4. Select \"Reset\""
  },
  {
    "path": "appops/guide/faq/purchase.md",
    "content": "# Purchase or restore problems\n\n## Google Play restore\n\nIn most cases, follow the prompts that appear after clicking the purchase. If you still can't solve the problem, please send us an email."
  },
  {
    "path": "appops/guide/technical/run_in_background.md",
    "content": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND` (Run in background)\n\n\"Run in background\" seen in the App Ops app actually refers to the two ops `RUN_IN_BACKGROUND` (added from Android 7) and `RUN_ANY_IN_BACKGROUND` (added from Android 9). Changing these ops will behave differently on different system versions.\n\nThis article will explain the effect of modifying `RUN_IN_BACKGROUND` and `RUN_ANY_IN_BACKGROUND` on app behavior on Android 9.\n\n## Special handling by the app App Ops\n\nIn response to the new addition of `RUN_ANY_IN_BACKGROUND` for Android 9, App Ops v2.6.0 used a strategy like this: directly treat `RUN_IN_BACKGROUND` and `RUN_ANY_IN_BACKGROUND` as the same one, ie only see a \"Run in background\" option, modify it will modify both two ops at the same time. However, in some special cases, setting two at the same time will cause the restriction to be too strict, so you can choose which one to limit from v2.6.0.\n\n## `RUN_IN_BACKGROUND`\n\n> The article has not been completed, more information will be added later\n\nAll apps targeting API 26 and above will always subject to this restriction.\n\nRefer to the following article:\n\nHttps://developer.android.com/about/versions/oreo/background\n\n## `RUN_ANY_IN_BACKGROUND`\n\n> The article has not been completed, more information will be added later\n\nRefer to the following article:\n\nHttps://developer.android.com/about/versions/pie/power#battery-saver\n\nHttps://developer.android.com/topic/performance/power/power-details\n\nSome of the commits involved:\n\nHttps://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18\n\nHttps://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16"
  },
  {
    "path": "appops/guide/technical/system_behaviors.md",
    "content": "# Difference under different Android versions\n\nEach op has two modes, `package mode` and `uid mode`. `uid mode` has higher priority, that is, `package mode` is used only when `uid mode` is the default value.\n\nThe following forms shows how the `uid mode` will be set when the permission settings are modified from the system.\n\n::: details Forms\n<p>\n\nThe asterisk (*) indicates changes from the previous system.\n\n#### Android 6 - Android 9\n| System setting page | uid mode                                |\n|---------------------|-----------------------------------------|\n| Allow               | allow                                   |\n| Deny                | ignore<br>(only for apps target pre-23) |\n| (Not yet set)       | (allow)                                 |\n\n#### Android 10\n\n| System setting page      | uid mode   |\n|--------------------------|------------|\n| Allow only while using * | foreground |\n| Allow                    | allow      |\n| Deny *                   | ignore     |\n| (Not yet set)            | (allow)    |\n\n#### Android 11\n\n| System setting page      | uid mode   |\n|--------------------------|------------|\n| Ask every time *         | ignore     |\n| Allow only while using * | foreground |\n| Allow                    | allow      |\n| Deny                     | ignore     |\n| (Not yet set) *          | ignore     |\n\n#### Other behaviors on Android 11\n\n* Setting `package mode` is invalid\n* When setting `uid mode`, it is invalid if the set value does not match to the runtime permission status\n* Under certain circumstances (for example, install an app), the system will reset the appops of **all apps** to states that match runtime permissions\n\n:::\n\n### The old version of App Ops didn't do it right\n\nThe old versions of App Ops (before v5.0.0) will only read and modify `package mode`, which is obviously wrong.\n\nIn Android 9 and before, it is invalid to set \"Allow\" in App Ops for apps target below 23. In Android 10, once the user sets \"Deny\" or \"Allow only while using\" in the system, the settings in App Ops will never take effect (because `uid mode` set by the system is used first).\n\nSince the system's permission settings were retained when upgrading from a lower version, this huge problem was slowly exposed one year after Android 10 was released.\n\n### Changes made in the new version (v5.0.0) of App Ops\n\nThere is no choice but to follow the behavior of the system completely.\n\nIn addition, since Android 11 will reset appops settings (all \"runtime permission allowed, ops ignored\" will be reset to \"runtime permission denied\"), so there is no choice but to reset later after the system.\n\n### The new version (v5.0.0) App Ops needs more capabilities\n\nTo follow the system behavior correctly, App Ops must have the ability to read and set `runtime permission`, `permission flags`, and `appops`. However, not all working modes can do it.\n\n|                    | Shizuku mode | Delegated Device Admin mode    | root mode (removed) |\n|--------------------|--------------|--------------------------------|---------------------|\n| appops             | ✔️            | ✔️                              | ✔️                   |\n| runtime permission | ✔️            | \"Set\" only<sup>**〔1〕**</sup> | ❌                   |\n| permission flags   | ✔️            | ❌                              | ❌                   |\n\n<sub><b>〔1〕</b>Requires Island v5.0+ or any other admin apps with [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) v3 support</sub>\n\n#### Defects of \"Delegated Device Admin mode\"\n\n* \"Unable to confirm\"\n* Cannot backup all settings\n* In Android 11, the new \"Ask every time\" cannot be set (requires \"set permission flags\")\n\n::: details Technical information\n\nAdministrator apps set as `profile owner` or `device owner` have some privileges, but only they can use them. Therefore, different admin apps provide different APIs, allowing other apps to \"borrow\" their privileges.\n\n* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)\n* [Delegation API](https://island.oasisfeng.com/api)\n\nOnly Island v5.0+ that provides Delegation API supports \"set runtime permission\".\n\nFor \"unable to confirm\", for example, in Android 10:\n\n|               | appops | runtime permission | permission flags |\n|---------------|--------|--------------------|------------------|\n| Ignore        | ignore | true               |                  |\n| Deny          | (any)  | false              | any \"FIXED\" flag |\n| (Not yet set) | (any)  | false              | no \"FIXED\" flag  |\n\nJust looking at the appops setting is obviously not enough.\n\n:::\n\n#### Why \"root mode\" has to be removed?\n\nThe ability of pure root (execution command) is very limited, there is no command that can modify `permission flags`. If you want to modify the `runtime permission` correctly, you must ensure that the `permission flags` are also modified correctly (the higher-level Java API used by device admins does not need to consider this issue).\n\nTherefore, the root mode has been removed.\n\n::: details Technical information\n\nMany people think that root is omnipotent, but in fact root basically only provides a shell with `uid 0`. If you want to enter the Android world (use Java API directly), running dex through `app_process` is almost the only option.\n\nThe alternative of \"root mode\", \"Shizuku mode\", uses Shizuku ([GitHub](https://github.com/RikkaApps/Shizuku)) to do this part of the work. If not Shizuku, something like Shizuku still need to be run, doing this is meaningless and will also bring meaningless resource usage.\n:::"
  },
  {
    "path": "appops/guide/working_mode/dpm.md",
    "content": "# Delegated Device Admin mode\n\n::: warning Warning\n\nAs of 6.0.0, this working mode is no longer supported. To continue using this working mode, please [download version 5.5.6](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/download/files/appops-v5.5.6.r1453.f44c5855.apk).\n\n:::\n\n## Requirements and Features\n\n* Requires Android 9+\n* Need to install other apps and use adb to set it as Device owner\n* Multi-user support depends on the Device owner app\n\n## Background\n\nDelegated Device Admin mode is a new working mode that App Ops has added since v2.9.0. Starting with Android 9, Device admin apps can modify appops settings, but the system limits the ability to set only one app as a Device admin on a device. Therefore, the App Ops app chooses to use APIs provided by other Device admin apps.\n\nFrom v2.9.0, App Ops supports Device admin apps using [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager).\n\nFrom v2.9.8, App Ops supports [another API provided by Island app](https://island.oasisfeng.com/api).\n\n## Disclaimer\n\nThe Device admin app you need to install is not developed by us.\n\n::: warning\nDevice admin have somewhat problems with Samsung devices and many devices from mainland China. Please be sure to read the help provided by the Device admin app. If you can't accept possible problems, please don't use them.\n:::\n\n::: danger\nSamsung devices may cause irreparable results after using the Device admin (see [Document from IceBox](https://iceboxdoc.catchingnow.com/Device%20Owner%20%E4%B8%89%E6%98%9F%E7%89%B9%E5%88%AB%E8%AF%B4%E6%98%8E)), **please be cautious**.\n:::\n\n## How to use\n\nThe setup process requires a computer to be use adb, but only needs to be set once.\n\n### 1. Install and set up the Device admin app\n\n#### IceBox\n\n1. Download from [Google Play](https://play.google.com/store/apps/details?id=com.catchingnow.icebox) or [Coolapk](https://www.coolapk.com/apk/com.catchingnow.icebox)\n2. See [Help](https://iceboxdoc.catchingnow.com/Device%20Owner%20(Non%20Root)%20Setup) to set up Device admin mode for it\n\n#### 小黑屋 (Simplified Chinese only)\n\n1. Download from [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) or [Coolapk](https://www.coolapk.com/apk/web1n.stopapp )\n2. See [Help](https://github.com/web1n/Stopapp-Docs/blob/master/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE.md) (Simplified Chinese only) to set up Device admin mode for it\n\n#### Island\n\n1. Download from [Google Play](https://play.google.com/store/apps/details?id=com.oasisfeng.island) or [Coolapk](https://www.coolapk.com/apk/com.oasisfeng.island)\n2. See [Help](https://island.oasisfeng.com/setup.html) to set up Device admin mode for it (Island call it \"God mode\")\n\n### 2. Granting permissions\n\nIn the \"Settings\" - \"Working Mode\" of App Ops, select \"Delegated Device Admin mode\" and return to the app list. The authorization dialog from the Device admin app should pop up. Please check \"change app ops\" and confirm.\n\nNext, you'll also need to grant App Ops the \"get app ops\" permission using adb. Use the following command:\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS\n```\n\nNote that if you install the App Ops app in other users, you need to replace the `0` of `--user 0` with the id of the other user (use `adb shell pm list users` you will see results like `UserInfo{0:Owner:13} running`, `0` from it is the user id).\n\n### 3. Granting multi-user permissions\n\nFor multi-user support, you also need to execute the following command to allow App Ops to partially access other users:\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS\n```\n\n::: tip\nCurrently only Island 3.8+ supports multiple users\n:::\n\n### 4. Have trouble?\n\n* `Cannot request permission without a restrictions provider registered` when using Island\n\n  Clear cache of Island (App info -> Storage -> Clear cache) and restart Island."
  },
  {
    "path": "appops/guide/working_mode/shizuku.md",
    "content": "# Shizuku mode\n\n## Requirements and Features\n\n* Need to install Shizuku app and start Shizuku service via adb or root\n* Support multi-user\n\n::: tip\nIf you use adb, you need to use adb to start Shizuku every time your device boot (**but the appops settings always take effect**)\n:::\n\n## Background\n\nShizuku is a free and [open-sourced](https://github.com/RikkaApps/Shizuku) framework-like app. It's designed to serve multiple apps which requires root or adb. With minimal performance impact, Shizuku significantly improve the performance and reliability of apps using Shizuku. Also, Shizuku provides great convenience for developers.\n\n> For information about Shizuku and the reason of making an application separately, please check [shizuku.rikka.app](https://shizuku.rikka.app/)."
  },
  {
    "path": "appops/zh-hans/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 立即下载\nactionLink: /zh-hans/download.html\nsecondaryActionText: 了解更多\nsecondaryActionLink: /zh-hans/guide/\nfeatures:\n- title: 访问隐藏的权限机制\n  details: 借助 App Ops 修改隐藏的 appops 设置来（部分）控制权限。\n- title: 优秀的用户体验\n  details: 提供美观、友好的用户界面。App Ops 在很多不为人知的地方做出许多努力以降低使用难度。\n- title: 无需 root 也可使用\n  details: 提供多种只需 adb 的工作模式。\n- title: 跟随最新的 Android 系统\n  details: 支持新版本 Android 的特性，即使是测试版系统也会在几天内得到支持。\n- title: 详细的帮助\n  details: 提供详细的帮助文档。\n- title: 提供高级功能\n  details: 借助模板、备份恢复等功能来方便操作。\nfooter: Copyright © 2019 RikkaApps\n---"
  },
  {
    "path": "appops/zh-hans/changelog.md",
    "content": "# 变更日志\n\n## 9.0.6 (2023-08-03)\n\n- 升级 Shizuku 到 13.5.0 以上可能可以解决自动化功能不工作的问题\n- 修复在部分 realme 设备上“无法启动服务”的问题\n- 修复在 Android 7.1 及之前版本崩溃\n\n## 9.0.0 (2023-04-08)\n\n- 为 Android 10 及以上版本添加“传感器”权限，可控制应用是否可以使用加速度计、重力传感器等无需权限即可使用的传感器\n- 支持 Android 14（但是，根据经验，应用程序很可能会因为之后的改动再次无法工作）\n- 在 Android 11 以上针对目标 API 为 30 及以上的应用隐藏 `OP_TOAST_WINDOW`，因为其不再有效\n- 在 Android 10 以上针对存储权限添加说明，因为系统允许特定的应用写入标准文件夹，即使其没有存储权限（特定的应用是指目标 API 是 30 或以上，或者目标 API 是 29 且适配了分区存储的应用）\n- 增加允许备份系统组件的选项\n- 针对中日韩语言用户，如果系统没有提供 Medium（500）字重的字体，则会使用模拟实现\n- 针对在三星设备上出现的 `com.android.externalstorage`、`com.android.providers.downloads`、`com.samsung.android.providers.media` 无权限问题增加提示信息\n\n## 8.0.1 (2022-11-22)\n\n- 未解锁完整版时允许备份（恢复备份仍需要完整版）\n- 修复切换用户随机失效\n\n## 8.0.0 (2022-09-02)\n\n- 针对 Android 12 及以上的实验性功能：使用情况历史\n- 适配 Android 12 关于位置权限的变化\n- Material Design 3\n- 设备管理员模式因为 Google Play 政策变化而被移除\n\n## 5.5.6 (2022-06-10)\n\n- 在 Android 13 Beta 3 上工作\n- 修复使用法语时崩溃的问题\n- 设备管理员模式将要因为 Google Play 政策变化而被移除\n  \n## 5.5.2 (2022-03-10)\n\n- 更换应用图标，因为旧图标“违反 Google Play 政策”\n\n## 5.5.0 (2022-03-03)\n\n- 在 Android 13 DP1 上工作（但是，根据经验，DP1 是非常早期的版本，应用程序很可能会因为 DP2 的改动再次无法工作）\n\n## 5.4.3 (2021-06-13)\n\n- 修复“自动恢复”可能造成所有同组权限都被重设为“忽略”的问题\n\n## 5.4.2 (2021-06-01)\n\n- 修复从 5.4.0 起备份坏掉\n- 修复低版本系统上的一些视觉问题\n\n## 5.4.0 (2021-05-27)\n\n- 修复在 Android 12 Beta 1 上剪贴板监视器不工作的问题\n- 修复在 Android 11 及以上版本，无法为安装在工作资料的应用设置“忽略”的问题（此修复只在 Shizuku 模式下可能）\n- 隐藏 `OP_QUERY_ALL_PACKAGES` 因为完全没有用\n- 隐藏 `OP_NO_ISOLATED_STORAGE` 因为它只用作调试\n\n## 5.3.3 (2021-05-04)\n\n- 适应另一个 Android 12 的改变\n- 阻止 💩 MIUI 的“强制深色模式”弄坏自己的深色主题<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI 有自己的“强制深色主题”，但是似乎即使应用正确地提供了深色主题，它也会继续起作用，从而把颜色改乱。</sub>\n\n## 5.3.1 (2021-04-03)\n\n- 修了一个可能导致崩溃的问题\n- 适应一些 Android 12 的改变\n\n## 5.3.0 (2021-01-28)\n\n- 初步地加入正确处理 Shared user ID\n\n## 5.2.0 (2021-01-16)\n\n- 支持 Sui（https://github.com/RikkaApps/Sui）\n\n## 5.1.3 (2020-11-29)\n\n- 适应了“存储空间隔离” v5 的变化\n- 修了如果系统返回了“错误”的数据备份会坏掉的问题（但是已经坏了的备份文件不可能修好）\n\n## 5.1.2 (2020-10-07)\n\n- 修复一个涉及创建备份的问题\n- 修复一个涉及“剪贴板监视器”的问题\n- 修复“自动恢复”的记录有时可能无法正确地被更新的问题\n- 导入来自用户的翻译\n\n## 5.1.0 (2020-09-24)\n\n- “应用详情”及“权限视图”的批量操作现在可以使用所有的选项（注意，选中多个项目时，显示的选项为所有可用选项的交集）\n- “权限视图”可以搜索\n\n## 5.0.6 (2020-09-06)\n\n- 修复一个有关创建备份的问题\n- 修复一个有关批量操作（包括使用模板、备份等）的问题\n- 导入来自用户的翻译\n- 其他小改变\n\n## 5.0.4 (2020-08-30)\n\n- 修复了实际上未还原任何内容时“正在还原备份”也可能会显示的问题\n- 导入来自用户的翻译\n- 其他小改变\n\n## 5.0.3 (2020-08-27)\n\n- 修复 v5.0.2 (1236) 引入的问题\n\n## 5.0.2 (2020-08-26)\n\n- 为所有 Android 10 强制使用“自动恢复”选项，因为已确认 Android 10 也会进行重置（只是相较 Android 11 情况更少）\n- 修复了在“托管设备管理员模式”下错误地要求所有版本的 Island 请求了只有 Island 5.0+ 提供的功能的问题\n- 修复了“自动恢复”的忽略选项实际上不起作用的问题\n- 修复了模板中的 `RUN_IN_BACKGROUND` 在编辑后没有正确显示的问题\n\n## 5.0.1 (2020-08-24)\n\n- 修了上个版本将使用 DSM API v3 的管理员应用错误地标明为“缺少支持”的问题\n- 修了上个版本的模板并没有正确显示所有选项\n- 修了上个版本针对（以“隐藏”为原理的）冻结类应用的自动恢复备份功能坏掉的问题\n- 在必要时重设 package mode（针对使用旧版 App Ops 或其他尚未正确适应系统变化的 appops 工具留下的“错误”设置）\n- 导入新增的用户翻译\n\n## 5.0.0 (2020-08-22)\n\n此更新解决了一个隐蔽但长期存在的问题。因为 Android 10 以下只在极少情况才出现，且升级到 Android 10 以后已有的设定不会被影响，这个问题在最近才浮出水面。一个典型的例子是，在 Android 10 中，一旦您从系统更改了位置权限，对旧版 App Ops 的更改将永远无法生效（即使看起来成功地更改了）。\n\n这背后包含很多工作，请阅读[技术细节](./guide/technical/system_behaviors/)。\n\n**您应该知道的内容：**\n\n- 您在 App Ops 中看到或更改的内容现在反映最终状态\n- 旧版本中的“拒绝”被重命名为“忽略”\n- 不再支持旧备份，因为它们缺少必要的信息（甚至可能包含错误的信息）\n- 对于“托管设备管理员模式”，当前只有 Island v5.0+ 支持新的必要的 API\n- 对于“托管设备管理员模式”，备份的一部分来源于历史用户操作，这是因为管理员应用没有足够的权限来获取准确的状态（这是系统限制）\n\n其他变化：\n\n- 添加自动恢复功能：针对 Android 11 和部分高度修改的系统（MIUI，Oxygen 等）会自动复原设置的系统\n- 模板：不止“忽略”（“拒绝”），现在可以在模板中使用任何选项\n- 备份：还原时更加灵活\n- 使用情况监控器：尝试减少“错误”报告（有时系统始终报告应用正在使用“位置”，即使该应用已经不再运行也是如此）\n- 使用情况监控器 & 剪贴板监视器：加入“排除系统应用”选项\n\n## 4.2.3 (2020-07-18)\n\n- Add Turkish translation\n- \"Usage monitor\" fix\n\n## 4.2.2 (2020-07-16)\n\n- 解决了从 v4.0.0 起出现的小概率随机停止运行问题\n- “使用情况监视器”改进\n- 重新整理字符串，任何人都可以参与翻译\n\n## 4.2.0 (2020-07-12)\n\n- 增加“使用情况监视器”（需要 Android 9 以上和通过 root 启动的 Shizuku）\n\n  当应用使用位置、相机或麦克风时收到提示\n\n## 4.1.1 (2020-07-10)\n\n- 剪贴板监视：可设定“临时访问时限”\n- 剪贴板监视：修复一个有关“排除的应用”的 UI 问题\n- 修复在 Android 10 以上，从 v4.0.0 起建立的备份可能损坏的问题\n- 正确地回报来自托管设备管理员模式的错误\n- 暂时不使用 AAPT2 的资源优化功能，这可能可以解决部分用户出现的随机的设置界面崩溃问题\n\n## 4.1.0 (2020-07-09)\n\n- 剪贴板监视：增加“窗口位置”和“排除的应用”选项\n- 修复一旦主要进程死掉，“新应用行为”功能就会停止工作\n- 修复权限视图 UI 刷新问题\n\n## 4.0.1 (2020-07-05)\n\n- 修复在某些情况下监视服务非正常地启动\n\n## 4.0.0 (2020-07-04)\n\n用最新技术（部分）重写。具有更多改进和新功能的全面重写将在不久的将来出现。\n\n- 新功能：剪贴板监视（需要 Android 10 以上和通过 root 启动的 Shizuku）<sup>**〔1〕**</sup>\n- 在 Android 10 及 11 上工作\n- 用户界面翻新\n- 修复一个有关恢复备份的问题\n- 永远使用内置的名称<sup>**〔2〕**</sup>\n- 对于免费版本，移除 Google Ads（转而推荐我们的其他应用）\n- 对于崩溃报告，使用 AppCenter 替代 Firebase Crashlytics（此外，崩溃报告可关闭）\n- 目标 API 30\n- 不再支持系统插件模式\n- 不再支持 Android 6.0\n- 不再支持古老的以 LineageOS 为基础的 ROM 中的询问模式<sup>**〔3〕**</sup>\n\n<sub><b>〔1〕</b>从监视中排除应用的功能将在下个版本中加入</sub>\n<br><sub><b>〔2〕</b>之前，“权限”的名称被优先使用。但是随着 Android 在每个版本间不断改变权限名称，权限名称越来越不准确。</sub>\n<br><sub><b>〔3〕</b>根据用户报告，一些老旧的三星设备表现得有这个功能，但是改为“询问”将会导致系统无法启动。</sub>\n\n## 3.1.1 (2019-08-03)\n\n- 修复无法编辑模板\n\n## 3.1.0 (2019-08-02)\n\n- 操作系统应用时提供更加明显的警告\n- 为套用模板对话框提供编辑与添加功能\n- 修复使用托管设备管理员模式时，如果先使用 Island 之后更换为其他也会被判定为正在使用 Island\n\n## 3.0.3 (2019-07-29)\n\n- 小 bug 修复\n- 提供新的包含文档的网站：<https://appops.rikka.app/zh-hant>\n\n## 3.0.2\n\n- 修复托管设备管理员模式坏掉\n- 修复错误的依赖\n\n## 3.0.0\n\n- 托管设备管理员模式：修复当使用 Island 时新应用安装可能不被出发\n- （实验性）托管设备管理员模式：支持多用户（需要 Island 3.8+ 作为设备管理员，2019/7/24 在 Google Play alpha 通道提供)\n- 模板：默认勾选“跳过检查”\n- 模板：改进编辑 UI\n- 如果一个 op 不被原生 Android 包含，显示提示\n- 其他 bug 修复和 UI 改进\n\n## 2.9.9\n\n- 托管设备管理员模式：修复一些与 Island 支持有关的 bug\n- 特权模式：修复总是需要旧式 Shizuku\n- 显示所有工作模式（解释原因如果不支持）\n\n## 2.9.8\n\n- （实验性）托管设备管理员模式支持 Island 应用的“上帝模式” (com.oasisfeng.island)\n- 特权模式：修复“adb 权限不足”提示从未显示（主要只给 MIUI）\n\n## 2.9.7\n\n- Try to fix \"Code 5\"\n\n## 2.9.5\n\n- Bring back access/reject time for Android Q beta 4 (but as Android Q changed data format and not open sourced yet, no detailed times like Android 9)\n- Fix \"Code 5 debug message: null\" (by upgrading lib from Google :(\n- Minor UI tweaks\n\n## 2.9.4\n\n- Target 29\n- 修 2.9.2 带来的 bug\n\n## 2.9.2\n\n- 修复升级到 2.9.1 后模板丢失\n- 通知语言现在应该完美跟随应用内语言设置\n\n## 2.9.1\n\n- 增加托管设备管理员模式（使用来自支持的设备管理员应用的 API）\n- 修一些 bug\n- 备份包含模板\n\n## 2.8.2\n\n- 修复 root 模式在 Android Q beta 3 上不工作\n- 修复在低版本 Android 上少数功能可能不正常\n- 修复“显示框架应用”选项在 root 模式下不工作\n- 修复 root 模式下 overlay package 们没有被过滤\n\n## 2.8.1\n\n- 在 Android Q beta 3 上能用（但还不能看使用时间）\n- 存储空间选项在 Q beta 3 上无效，这是系统 bug\n- 暂时在 Q beta 3 上隐藏“存储空间沙盒”选项（默认关闭除非应用声明，如何强制开启方法尚不明确）\n- 当未设定默认模板时自动设定第一个（用于拯救从不阅读提示的傻子）\n\n## 2.8.0\n\n- 支持 Android Q 添加的新 op\n- UI 改进\n\n## 2.7.0\n\n- 在 Android 9 上再也不会出现“需要重启应用”\n- 使用特权模式时不再会出现随机错误（需要升级到 Shizuku v3 并强行停止 App Ops）\n\n## 2.6.4\n\n- 更新其他语言的翻译\n- 修复 bug\n\n## 2.6.3\n\n- 更新其他语言的翻译\n- 修复 bug\n\n## 2.6.2\n\n- root 模式支持多用户（实验性）\n- 为根据权限分组的列表加入“已禁用有限”选项\n- 为 Android 9 用户优化控制“在后台运行”时的 UI\n- 修复 bug\n\n## 2.5.10\n\n- 增加为 Android 9 准备的帮助\n- 修复 bug\n\n## 2.5.9\n\n- 修复一个涉及多用户的 bug\n\n## 2.5.8\n\n- 修复 bug\n\n## 2.5.7\n\n- 简化详情界面 UI\n- 修复当一些 op 的 opToSwitch 所对应的权限没有申请时就无法更改那些 op 的 bug\n\n## 2.5.5\n\n- 修复无 root 在 Android 9 上首次使用特权模式的流程\n- 修复编辑中的模板如果进行旋转屏幕等操作会丢失已编辑内容的问题\n- 编辑模板按下返回会询问是否保存\n- 修复在模板名称按下回车会爆炸\n- 默认隐藏未知的 op（对，又是你 MIUI）\n\n## 2.5.3\n\n- 修复一些关于新应用监控的问题\n- 可能修复一些打开就爆炸\n\n## 2.5.2\n\n- 修复在 2.5.0 中系统插件模式无法使用\n- 修复错误信息没有被正确展示\n- 修复在 Android 7.x 上无法正常工作\n- 修复部分 Google Play 用户会出现“您已拥有此物品”的问题\n- 为了让监控新应用安装功能更加可靠，现在它需要运行一个前台服务（仅 Android 8.0 以上），\n  但你可以禁用或将其设定为最低重要程度来避免被打扰\n\n## 2.5.0\n\n- 为 Android 9+ 移除系统插件（因为只有在插件拥有系统签名时才能工作）\n- 简化系统插件安装，只提供 zip 下载\n- 支持 Android 9 添加的 appops 特性（如 MODE_FOREGROUND 和 OP_RUN_ANY_IN_BACKGROUND）\n- 新的 UI\n- 多组模板\n- 解决当长时间后返回， app 无法使用的问题\n\n## 2.4.1\n\n- 更新翻译\n- 尝试修复部分付费用户会被当作未付费用户的问题\n\n## 2.4.0\n\n- 提升 root 模式速度\n\n## 2.3.13\n\n- 尝试修复 root 模式在部分设备无法工作\n- 改变 Android 8+ 上的图标\n\n## 2.3.12\n\n- 尝试修复在恢复备份时可能崩溃\n\n## 2.3.11\n\n- 为所有列表添加全选（长按 -> 菜单里的三个点点 -> 全选）\n- 系统插件模式现在为 Magisk 用户提供 template v1500 的模块\n\n## 2.3.10\n\n- 修复当恢复大量备份时崩溃\n- 修复提示对话框内容不可以滚动的问题\n\n## 2.3.9\n\n- 修了在 Android P DP1 上崩溃（你可能会看到 \"Detect problems with API compatibility\" 的提示，但是对 App Ops 来说不使用隐藏 API 是不可能的）\n\n## 2.3.8\n\n- 增加“显示全部模式”选项（不懂是什么就别打开）\n\n## 2.3.7\n\n- _始终显示权限（操作）_ 将会排除一些绝对不可能的情况\n- 增加被安装到外部存储的错误提示（都 8012 了怎么还有这种人）\n- 更新葡萄牙语（巴西）翻译\n- 移除一些未使用资源\n- 修复创建备份坏掉\n\n## 2.3.6\n\n- 修了总是提示 Google play 不可用\n- 增加一个显示全部支持的权限（操作）的列表\n- 在应用列表中标记系统应用\n- 增加 _始终显示的权限（操作）_ 列表，每个应用都会被当作可能使用选中的权限\n- 调整设置 UI\n\n## 2.3.5\n\n- 修复备份预览坏掉\n- 增加本地网络（特权模式需要使用）受限时的提示\n- 处理一些未捕获的错误\n\n## 2.3.4\n\n- 修复 root 模式下重置无效的问题（真·上古 bug）\n- 修复从应用列表重置或应用模板不会刷新 UI 的问题\n\n## 2.3.3\n\n- 修了两个上古 bug\n\n## 2.3.2\n\n- 修了 2.3.0 留下的 bug\n- 异步读取其他信息（比如已修改的项数），因此现在读取应用列表速度会非常快\n\n## 2.3.0\n\n- 为应用列表增加已修改的项数\n- 极大加速 root 模式下获取 appops 配置的速度\n- Oreo 风格的应用详情视图\n- 支持 Android 8.1 的亮色导航栏\n- 修改一些令人疑惑的 UI\n- (免费用户) 因为 Google 将在 2018 年 3 月后移除快捷原生广告，所以换回旧的横幅广告\n- 修复一些和多用户有关的问题\n- (付费用户) 修复在应用安装后，即使备份存在且打开了恢复备份，只要模板存在就被套用的问题\n- 因为一些原因，移除对旧的 Shizuku （特权模式）的支持\n\n## 2.2.6\n- 修复 Shizuku Manager 比 App Ops 安装晚会无法使用的问题\n\n## 2.2.5\n- 为新应用监控添加开机启动\n- 添加 Portuguese (Brazil) 语言\n\n## 2.2.4\n- 增加针对 adb 有读取 appops 配置但没有写入权限时的提示（比如 MIUI MIUI 和 MIUI）\n- 使用新的 build tool 来避免一个只在部分低版本第三方 ROM 上出现的可怕的问题 ([看这里](https://issuetracker.google.com/issues/64434571))\n\n## 2.2.3\n\n- 修复_特权模式_使用旧版 _Shizuku Manager_ 可能会崩溃的问题\n- 从通知套用模板时不再检查是否有 `RUN_IN_BACKGROUND`\n- 修复切换工作模式时设置崩溃\n\n## 2.2.2\n\n- 修复选择_特权模式_时没有安装 _Shizuku Manager_ 会崩溃\n\n## 2.2.1\n\n- 增加指定界面语言的功能\n- 更新翻译\n- 通过反射 `PackageInfo#overlayTarget` 的方式过滤 overlay apps\n- 修了新应用通知上的按钮在部分设备上可能不能用的问题\n- 套用模板时不再检查是否有 `RUN_IN_BACKGROUND`\n\n## 2.2.0\n\n- 修复套用模板或恢复备份后通知不能消除的问题\n- 重新规划主菜单项目\n- 将“显示框架应用”移至主菜单\n- 增加“根据更新时间排序”，“根据安装时间排序”\n- 实验室增加 \"Show target 0 apps\" (为了过滤掉 substratum overlay)\n- 重构设置向导，同时增加更多说明\n- 调整设置 UI\n- 修复通知不能显示自适应图标 (8.0+)\n\n## 2.1.12 (beta)\n\n- 在获取应用列表是请求更少数据\n\n> 解决部分设备上只能获得部分应用（甚至出现 \"Package Manager has died\"）的问题。\n\n> 会加快列表刷新速度。\n\n> 但没有那些数据，we have to remove \"show apps without icon\" option because we can't know\nif the app have a entrance, and \"run in background\" (Android 7.0+) will always shown because we can't\nspeculated if the app have background behavior.\n\n- （特权模式）让 Shizuku manager 展示服务没有运行\n- 新的版本号明明规则\n- 适配 Font Provider API v8\n\n## 2.1.11\n\n- Fix system plugin broadcast does not work\n- Fix notification didn't show when plugin stopped\n- Improve Settings UI for RTL language\n- 引入 Shizuku v2 (特权模式)，加入 Shizuku Manager 的测试来尝试\n- Font Provider 默认开启\n\n## 2.1.10\n\n- 当系统插件权限不足时给用户更友好的提示\n- 再次修复使用系统插件时有时需要手动刷新\n- 更新 Font Provider 依赖到 1.3.2，应该没问题了\n- 增加更多帮助\n- 修了一些对话框的按钮颜色\n\n## 2.1.9\n\n- Fix NPE in WorkService\n- Move system plugin download to GitHub release\n- Fix crash when open help in runtime permission tip dialog\n- Notify list refresh when system plugin connected\n- Update translation\n- Add translator's name to about\n\n## 2.1.2 - 2.1.8\n\n- 修复无法创建备份文件\n- 实验室（包含未确定或实验性功能）功能入口现在总是显示\n- Provide fastScroll drawable from AOSP to avoid crash on some devices\n- Update help\n- Fix test link in pro version\n- 100% fix theme and night mode, it should work perfectly now\n- Update adaptive icon for Android O\n- Add tip of Runtime Permissions when entering app target 23+\n- 改进的主题\n- 提供一个新的选项来使用 \"Noto Sans CJK Medium\" 替换 \"sans-serif-medium\" 字体（需要配合 Font Provider 应用使用）\n- Add tip for users can't use system plugin on Android O\n\n## 2.1.1\n\n- 增强的备份功能 (PRO)\n  - 当用户改变权限设置后，设置会被自动保存至数据库。当应用在卸载后再次安装或是被使用设备管理器的冻结类应用（如[冰箱](https://play.google.com/store/apps/details?id=com.catchingnow.icebox)的免 root模式）禁用后重新启用后可以选择恢复。\n- 增加详细的更新日志\n- 新的更详细的帮助"
  },
  {
    "path": "appops/zh-hans/download.md",
    "content": "# 下载\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com/apk/rikka.appops)\n\n[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)\n\n"
  },
  {
    "path": "appops/zh-hans/guide/README.md",
    "content": "# 了解 App Ops\n\n简而言之，**App Ops** 是一个修改 **Android 系统中的 \"appops\" 设置** 的应用。\n\n## 什么是 Android 系统中的 \"appops\"\n\n在 Android 系统中存在一个叫做 \"appops\" 的系统服务，该服务定义了一系列的“应用操作”(application operation, op)。其中部分“应用操作”与“权限”对应（如 `OP_CAMERA` 与“相机权限”），其余则对应单独的功能（如 `OP_READ_CLIPBOARD` 与读取剪贴板，但并不存在“读取剪贴板权限”）。\n\n原生 Android 系统使用 appops 来追踪权限使用，appops 也部分被用于权限控制。每个应用都有自己的 \"appops\" 设置，当应用需要执行某些操作时，系统在检查权限的同时也会检查 \"appops\" 设置。如果没有授予权限，应用在执行操作时将会收到错误。但不同的是，如果 \"appops\" 设为忽略<sup>**〔1〕**</sup>，应用不会收到错误只会收到空白数据<sup>**〔2〕**</sup>。\n\n但是原生 Android 系统并没有提供修改 \"appops\" 设置的用户界面。\n\n<sub>**〔1〕** App Ops 应用中实际将“忽略”显示为“拒绝”</sub>\n<br><sub>**〔2〕** 实际行为取决于系统，应用也可检查 \"appops\" 是否被拒绝</sub>\n\n## 什么是 App Ops 应用\n\nApp Ops 应用的核心功能是修改系统 \"appops\" 设置，可以在某种意义上实现权限管理。App Ops 应用还做出很多努力简化许多技术细节，让使用更加简单。\n\n## 用语声明\n\n### “权限”\n\nApp Ops 实际修改的是“应用操作”而非“权限”，但为了降低难度将其称为“权限”。App Ops 应用**不可以直接操作“权限”**，请不要误解。\n\n::: tip\n帮助中的其他地方仍称其为“权限”。\n:::\n## App Ops 的限制\n\n### 可以修改的权限取决于系统\n\nApp Ops 所能修改的权限**只取决于你的系统**，所以别再问“为什么没有 XXX 权限”了。\n\n通常，系统版本越高，能修改的内容越多（厂商或自定义 ROM 可能会添加自己的权限）。所有你的系统支持的权限可以在 设置 - 行为 - 全部权限 中看到。\n\n### 应用仍可以获知没有权限\n\n应用可以检查返回数据是否为空白，或是直接检查 \"appops\" 是否被允许。只是很少有应用这么做。"
  },
  {
    "path": "appops/zh-hans/guide/faq/how_to_reset.md",
    "content": "### 如何重置全部设置？\n\n1. 切换到应用列表模式\n2. 长按或点击左侧应用图标进入多选模式\n3. 右上方三点菜单 - 全选\n4. 选择“重置”"
  },
  {
    "path": "appops/zh-hans/guide/faq/purchase.md",
    "content": "# 购买或恢复问题\n\n## Google Play 恢复问题\n\n大部分情况下，按照点击购买后出现的提示文字处理即可，如果仍不能解决问题，请发送邮件给我们。"
  },
  {
    "path": "appops/zh-hans/guide/technical/run_in_background.md",
    "content": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`（在后台运行）\n\n在 App Ops 应用中看到的“在后台运行”实际是指 `RUN_IN_BACKGROUND`（Android 7 起增加）和 `RUN_ANY_IN_BACKGROUND`（Android 9 起增加）这两个 op。在不同的系统版本上，改变这些 op 会有不同的行为。\n\n这篇文章将会说明在 Android 9 上修改 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 对应用行为的影响。\n\n## App Ops 应用所做的特殊处理\n\n为了应对 Android 9 新增加的 `RUN_ANY_IN_BACKGROUND`，App Ops v2.6.0 以前采取这样的策略：直接将 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 视为同一个，即只会看到一个“在后台运行”选项，修改时会同时修改这两个。但部分特殊情况下，同时设置两个会造成限制过于严格的问题，因此从 v2.6.0 起可以自行选择限制哪一个。\n\n## `RUN_IN_BACKGROUND`\n\n> 文章尚未完成，更多信息将在以后补充\n\n所有 target API 在 26 及以上的应用会受到此限制。\n\n参考以下文章：\n\nhttps://developer.android.com/about/versions/oreo/background\n\n## `RUN_ANY_IN_BACKGROUND`\n\n> 文章尚未完成，更多信息将在以后补充\n\n参考以下文章：\n\nhttps://developer.android.com/about/versions/pie/power#battery-saver\n\nhttps://developer.android.com/topic/performance/power/power-details\n\n部分涉及的 commit：\n\nhttps://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18\n\nhttps://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16"
  },
  {
    "path": "appops/zh-hans/guide/technical/system_behaviors.md",
    "content": "# 不同 Android 版本下的不同\n\n每个 op 都有两种 mode，分别为 `package mode` 和 `uid mode`。`uid mode` **有更高优先级**，即只有当 `uid mode` 为默认值时才会使用 `package mode`。\n\n以下表格展示了从系统修改权限设定时，`uid mode` 会被如何设定。\n\n::: details 表格\n<p>\n\n星号（*）表示相对之前的系统放生变化。\n\n#### Android 6 - Android 9\n| 系统设定页面 | uid mode                                |\n|--------------|-----------------------------------------|\n| 允许         | allow                                   |\n| 拒绝         | ignore（只对 target 23 以下的应用设定） |\n| （尚未设定） | (allow)                                 |\n\n#### Android 10\n\n| 系统设定页面       | uid mode   |\n|--------------------|------------|\n| 仅在使用期间允许 * | foreground |\n| 允许               | allow      |\n| 拒绝 *             | ignore     |\n| （尚未设定）       | (allow)    |\n\n#### Android 11\n\n| 系统设定页面       | uid mode   |\n|--------------------|------------|\n| 每次都询问 *       | ignore     |\n| 仅在使用期间允许 * | foreground |\n| 允许               | allow      |\n| 拒绝               | ignore     |\n| （尚未设定）*      | ignore     |\n\n#### Android 11 中的其他行为\n\n* 设置 `package mode` 无效\n* 设置 `uid mode` 时，若设定值不符合运行时权限状态则无效\n* 在特定的情况下（比如安装应用后），系统将重设**全部应用**的 appops 设定到与运行时权限符合的状态\n\n:::\n\n### 旧版本 App Ops 没做对\n\n旧版本的 App Ops（v5.0.0 以前）只会读取和修改 `package mode`，这显然是不对的。\n\n在 Android 9 及之前，对 target 23 以下的应用在 App Ops 中设定“允许”是无效的；在 Android 10，一旦用户在系统中设置“拒绝”或“仅在使用时允许”，则在 App Ops 中的设置永远无法生效（因为此时系统设置的 `uid mode` 被优先使用）。\n\n由于从低版本升级时系统的权限设定是被保留的，这个巨大的问题在 Android 10 发布的一年后才慢慢地暴露出来。\n\n### 新版本（v5.0.0）App Ops 所做出的变化\n\n除了完全跟随系统行为以外别无选择。\n\n另外，因为 Android 11 会重置 appops 设定（所有“运行时权限允许，ops 忽略”会被重设为“运行时权限拒绝”），所以除了在系统之后再次重设以外别无选择。\n\n### 新版本（v5.0.0）App Ops 需要更多能力\n\n想要正确跟随系统行为，App Ops 必须具备取得和设置 `runtime permission`，`permission flags`，`appops` 的能力。但是，并不是所有工作模式都能做到。\n\n|                    | Shizuku 模式 | 托管设备管理员模式           | root 模式（已被移除） |\n|--------------------|--------------|------------------------------|-----------------------|\n| appops             | ✔️            | ✔️                            | ✔️                     |\n| runtime permission | ✔️            | 仅可设置<sup>**〔1〕**</sup> | ❌                     |\n| permission flags   | ✔️            | ❌                            | ❌                     |\n\n<sub><b>〔1〕</b>需要 Island v5.0+ 或其他具有 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) v3 支持的管理员应用</sub>\n\n#### “托管设备管理员模式”的缺陷\n\n* “无法确认”\n* 无法备份全部设置\n* 在 Android 11，无法设定新增的“每次都询问”（需要“设置 permission flags”）\n\n::: details 技术信息\n\n被设为 `profile owner` 或 `device owner` 的管理员应用享有一些特权，但是只有它们自身可以使用。因此，不同的管理员应用提供了不同的 API，使其他应用得以“借用”其特权。\n\n* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)\n* [Delegation API](https://island.oasisfeng.com/api)\n\n只有提供 Delegation API 的 Island v5.0+ 支持“设置 runtime permission”。\n\n对于“无法确认”，举个例子，在 Android 10 中：\n\n|              | appops     | runtime permission | permission flags |\n|--------------|------------|--------------------|------------------|\n| 忽略         | ignore     | true               |                  |\n| 拒绝         | （任何值） | false              | 任意 \"FIXED\"     |\n| （尚未设置） | （任何值） | false              | 无 \"FIXED\"       |\n\n只看 appops 设置显然不够。\n\n:::\n\n#### 为什么必须移除“root 模式”\n\n纯 root（执行指令）的能力十分有限，没有可以修改 permission flags 的指令。想要正确修改 runtime permission 必须保证 permission flags 也被正确地修改（设备管理员所使用的更高层级的 Java API 不需要考虑这个问题）。\n\n因此，root 模式已被移除。\n\n::: details 技术信息\n\n很多人会认为 root 无所不能，但实际上 root 只提供了一个 `uid 0` 的 shell。想要进入 Android 世界（直接使用 Java API），通过 `app_process` 运行 dex 几乎是唯一选择。\n\n“root 模式”的替代——“Shizuku 模式”使用 Shizuku（[GitHub](https://github.com/RikkaApps/Shizuku)）做这一部分的工作。如果不使用 Shizuku，则仍然需要运行类似 Shizuku 的东西，这样做是没有意义的，并且也将带来无意义的资源使用。\n\n:::"
  },
  {
    "path": "appops/zh-hans/guide/working_mode/dpm.md",
    "content": "# 托管设备管理员模式\n\n::: warning 警告\n\n从 6.0.0 起，此工作模式不再支持。若要继续使用此工作模式，请[下载 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/download/files/appops-v5.5.6.r1453.f44c5855.apk)。\n\n:::\n\n## 需求及特性\n\n* 需要 Android 9+\n* 需要安装其他应用，并使用 adb 将其设为 Device owner\n* 是否支持多用户取决于 Device owner 应用\n\n## 背景\n\n托管设备管理员模式是 App Ops 从 v2.9.0 开始加入的新的工作模式。从 Android 9 开始，设备管理员开始可以修改 appops 设定，但系统限制一台设备上仅能设置一个应用为设备管理员。因此 App Ops 使用由其他设备管理员应用提供的 API。\n\n从 v2.9.0 起支持使用 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) 的设备管理员应用。\n\n从 v2.9.8 起支持另一种[由 Island 提供的 API](https://island.oasisfeng.com/api)。\n\n## 免责声明\n\n你需要安装的设备管理员应用都不是由我们开发。\n\n::: warning\n设备管理员在三星设备及很多来自中国大陆地区厂商的设备上或多或少存在一些问题，请务必仔细阅读来自设备管理员应用提供的帮助，如果你无法接受可能的问题，请不要使用。\n:::\n\n::: danger\n三星设备在使用设备管理员后可能造成无法挽回的结果（参阅 [来自 冰箱 IceBox 的文档](https://iceboxdoc.catchingnow.com/Device%20Owner%20%E4%B8%89%E6%98%9F%E7%89%B9%E5%88%AB%E8%AF%B4%E6%98%8E)），请务必谨慎。\n:::\n\n## 如何使用\n\n设置过程需要连接电脑使用 adb，但只需要进行一次设置。\n\n### 1. 安装及设置设备管理员应用\n\n#### 冰箱 IceBox\n\n1. 下载 [Google Play](https://play.google.com/store/apps/details?id=com.catchingnow.icebox) 或 [Coolapk](https://www.coolapk.com/apk/com.catchingnow.icebox)\n2. 参阅 [帮助](https://iceboxdoc.catchingnow.com/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE) 为其设置设备管理员模式\n\n#### 小黑屋\n\n1. 下载 [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) 或 [Coolapk](https://www.coolapk.com/apk/web1n.stopapp)\n2. 参阅 [帮助](https://github.com/web1n/Stopapp-Docs/blob/master/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE.md)（仅提供简体中文） 为其设置设备管理员模式\n\n#### Island\n\n1. 下载 [Google Play](https://play.google.com/store/apps/details?id=com.oasisfeng.island) 或 [Coolapk](https://www.coolapk.com/apk/com.oasisfeng.island)\n2. 参阅 [帮助](https://island.oasisfeng.com/setup.html) 为其设置设备管理员模式（Island 称其为“上帝模式”）\n\n### 2. 授予权限\n\n在 App Ops “设置”-“工作模式”中选择“托管设备管理员模式”后返回应用列表应该会弹出来自设备管理员应用的授权对话框，请在勾选“修改 app ops”后确认。\n\n接着，你还需要使用使用 adb 授予 App Ops “获取 app ops” 权限。使用以下的指令：\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS\n```\n\n注意，如果你将 App Ops 应用安装到其他用户，需要将其中 `--user 0` 的 `0` 替换为其他用户的 id（使用 `adb shell pm list users` 获得的 `UserInfo{0:Owner:13} running` 的结果中的 `0` 即为用户 id）。\n\n### 3. 授予多用户权限\n\n对于多用户支持，你还需要运行下面的指令来让 App Ops 可以部分访问其他用户：\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS\n```\n\n::: tip\n目前只有 Island 3.8+ 支持多用户\n:::\n\n### 4. 遇到问题？\n\n* 使用 Island 时出现 `Cannot request permission without a restrictions provider registered`\n\n  清除 Island 的缓存（应用信息 -> 存储 -> 清除缓存），后重新启动 Island。"
  },
  {
    "path": "appops/zh-hans/guide/working_mode/shizuku.md",
    "content": "# Shizuku 模式\n\n## 需求及特性\n\n* 需要安装 Shizuku 应用并通过 adb 或 root 启动 Shizuku 服务\n* 支持多用户\n\n::: tip\n如果使用 adb，每次开机都需要使用 adb 进行启动 Shizuku 的步骤（**但 appops 设置总是生效**）\n:::\n\n## 背景\n\nShizuku 是一个免费且[开源](https://github.com/RikkaApps/Shizuku)的类似于框架的应用。它旨在服务多个需要 root 或 adb 的应用。Shizuku 在对性能的影响最小的情况下，极大地提高了使用 Shizuku 的应用的性能和可靠性。 此外，Shizuku 还为开发者提供了极大的便利。\n\n> 有关 Shizuku 的信息，以及为什么要独立出一个应用，请查看 [shizuku.rikka.app](https://shizuku.rikka.app/zh-hans)。"
  },
  {
    "path": "appops/zh-hant/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 立即下載\nactionLink: /zh-hant/download.html\nsecondaryActionText: 瞭解更多\nsecondaryActionLink: /zh-hant/guide/\nfeatures:\n- title: 訪問隱藏的權限機制\n  details: 藉助 App Ops 修改隱藏的 appops 設定來（部分）控制權限。\n- title: 優秀的使用者經驗\n  details: 提供美觀、友好的使用者介面。App Ops 在很多不為人知的地方做出許多努力以降低使用難度。\n- title: 無需 root 也可使用\n  details: 提供多種只需 adb 的工作模式。\n- title: 跟隨最新的 Android 系統\n  details: 支援新版本 Android 的特性，即使是測試版系統也會在幾天內得到支援。\n- title: 詳細的幫助\n  details: 提供詳細的幫助文件。\n- title: 提供高階功能\n  details: 藉助模板、備份恢復等功能來方便操作。\nfooter: Copyright © 2019 RikkaApps\n---"
  },
  {
    "path": "appops/zh-hant/changelog.md",
    "content": "# 變更日誌\n\n## 9.0.6 (2023-08-03)\n\n- 升級 Shizuku 到 13.5.0 以上可能可以解決自動化功能不工作的問題\n- 修復在部分 realme 裝置上「無法啟動服務」的問題\n- 修復在 Android 7.1 及之前版本崩潰\n\n## 9.0.0 (2023-04-08)\n\n- 為 Android 10 及以上版本新增「感測器」權限，可控制應用程式是否可以使用加速度計、重力感測器等無需權限即可使用的感測器\n- 支援 Android 14（但是，根據經驗，應用程式很可能會因為之後的改動再次無法工作）\n- 在 Android 11 以上針對目標 API 為 30 及以上的應用程式隱藏 `OP_TOAST_WINDOW`，因為其不再有效\n- 在 Android 10 以上針對儲存權限新增說明，因為系統允許特定的應用程式寫入標準資料夾，即使其沒有儲存權限（特定的應用程式是指目標 API 是 30 或以上，或者目標 API 是 29 且適配了 Scoped Storage 的應用程式）\n- 增加允許備份系統元件的選項\n- 針對中日韓語言使用者，如果系統沒有提供 Medium（500）字重的字型，則會使用模擬實現\n- 針對在三星裝置上出現的 `com.android.externalstorage`、`com.android.providers.downloads`、`com.samsung.android.providers.media` 無權限問題增加提示資訊\n\n## 8.0.1 (2022-11-22)\n\n- 未解鎖完整版時允許備份（恢復備份仍需要完整版）\n- 修復切換使用者隨機失效\n\n## 8.0.0 (2022-09-02)\n\n- 針對 Android 12 及以上的實驗性功能：使用情況歷史\n- 適配 Android 12 關於位置權限的變化\n- Material Design 3\n- 裝置管理員模式因為 Google Play 政策變化而被移除\n\n## 5.5.6 (2022-06-10)\n\n- 在 Android 13 Beta 3 上工作\n- 修復使用法語時崩潰的問題\n- 裝置管理員模式將要因為 Google Play 政策變化而被移除\n\n## 5.5.2 (2022-03-10)\n\n- 更換應用程式圖示，因為舊圖示「違反 Google Play 政策」\n\n## 5.5.0 (2022-03-03)\n\n- 在 Android 13 DP1 上工作（但是，根據經驗，DP1 是非常早期的版本，應用程序很可能會因為 DP2 的改動再次無法工作）\n\n## 5.4.3 (2021-06-13)\n\n- 修復「自動恢復」可能造成所有同組權限都被重設爲「忽略」的問題\n\n## 5.4.2 (2021-06-01)\n\n- 修復從 5.4.0 起備份不工作\n- 修復低版本系統上的一些視覺問題\n\n## 5.4.0 (2021-05-27)\n\n- 修復在 Android 12 Beta 1 上剪貼簿監視器不工作的問題\n- 修復在 Android 11 及以上版本，無法為安裝在工作資料的應用程式設定「忽略」的問題（此修復只在 Shizuku 模式下可能）\n- 隱藏 `OP_QUERY_ALL_PACKAGES` 因為完全沒有用\n- 隱藏 `OP_NO_ISOLATED_STORAGE` 因為它只用作除錯\n\n## 5.3.3 (2021-05-04)\n\n- 適應另一個 Android 12 的改變\n- 阻止 💩 MIUI 的「強制深色模式」弄壞自己的深色主題<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI 有自己的「強制深色模式」，但是似乎即使應用程式正確地提供了深色主題，它也會繼續起作用，從而把顏色改亂。</sub>\n\n## 5.3.1 (2021-04-03)\n\n- 修了一個可能導致崩潰的問題\n- 適應一些 Android 12 的改變\n\n## 5.3.0 (2021-01-28)\n\n- 初步地加入正確處理 Shared user ID\n\n## 5.2.0 (2021-01-16)\n\n- 支援 Sui（https://github.com/RikkaApps/Sui）\n\n## 5.1.3 (2020-11-29)\n\n- 適應了「儲存空間隔離」v5 的變化\n- 修瞭如果系統返回了「錯誤」的資料備份會壞掉的問題（但是已經壞了的備份檔案不可能修好）\n\n## 5.1.2 (2020-10-07)\n\n- 修復一個涉及建立備份的問題\n- 修復一個涉及「剪貼簿監視器」的問題\n- 修復「自動恢復」的記錄有時可能無法正確地被更新的問題\n- 匯入來自使用者的翻譯\n\n## 5.1.0 (2020-09-24)\n\n- 「應用詳情」及「權限檢視」的的批量操作現在可以使用所有的選項（注意，選中多個項目時，顯示的選項為所有可用選項的交集）\n- 「權限檢視」可以搜尋\n\n## 5.0.6 (2020-09-06)\n\n- 修復一個有關建立備份的問題\n- 修復一個有關批量操作（包括使用模板、備份等）的問題\n- 匯入來自使用者的翻譯\n- 其他小改變\n\n## 5.0.4 (2020-08-30)\n\n- 修復了實際上未還原任何內容時「正在還原備份」也可能會顯示的問題\n- 匯入來自使用者的翻譯\n- 其他小改變\n\n## 5.0.3 (2020-08-27)\n\n- 修復 v5.0.2 (1236) 引入的問題\n\n## 5.0.2 (2020-08-26)\n\n- 為所有 Android 10 強制使用「自動恢復」選項，因為已確認 Android 10 也會進行重置（只是相較 Android 11 情況更少）\n- 修復了在「託管裝置管理員模式」下錯誤地要求所有版本的 Island 請求了只有 Island 5.0+ 提供的功能的問題\n- 修復了「自動恢復」的忽略選項實際上不起作用的問題\n- 修復了模板中的 `RUN_IN_BACKGROUND` 在編輯後沒有正確顯示的問題\n\n## 5.0.1 (2020-08-24)\n\n- 修了上個版本將使用 DSM API v3 的管理員程式錯誤地標明為「缺少支援」的問題\n- 修了上個版本的模板並沒有正確顯示所有選項\n- 修了上個版本針對（以「隱藏」為原理的）凍結類應用的自動恢復備份功能壞掉的問題\n- 在必要時重設 package mode（針對使用舊版 App Ops 或其他尚未正確適應系統變化的 appops 工具留下的「錯誤」設定）\n- 匯入新增的使用者翻譯\n\n## 5.0.0 (2020-08-22)\n\n此更新解決了一個隱蔽但長期存在的問題。因為 Android 10 以下只在極少情況才出現，且升級到 Android 10 以後已有的設定不會被影響，這個問題在最近才浮出水面。一個典型的例子是，在 Android 10 中，一旦您從系統更改了位置權限，對舊版 App Ops 的更改將永遠無法生效（即使看起來成功地更改了）。\n\n這背後包含很多工作，請閱讀[技術細節](./guide/technical/system_behaviors/)。\n\n**您應該知道的內容：**\n\n- 您在 App Ops 中看到或更改的內容現在反映最終狀態\n- 舊版本中的「拒絕」被重新命名為「忽略」\n- 不再支援舊備份，因為它們缺少必要的資訊（甚至可能包含錯誤的資訊）\n- 對於「託管裝置管理員模式」，當前只有 Island v5.0+ 支援新的必要的 API\n- 對於「託管裝置管理員模式」，備份的一部分來源於歷史使用者操作，這是因為管理員程式沒有足夠的權限來獲取準確的狀態（這是系統限制）\n\n其他變化：\n\n- 模板：不止「忽略」（「拒絕」），現在可以在模板中使用任何選項\n- 備份：還原時更加靈活\n- 使用情況監控器：嘗試減少「錯誤」報告（有時系統始終報告應用程式正在使用位置，即使該應用程式已經不再執行也是如此）\n- 使用情況監控器 & 剪貼簿監視器：加入「排除系統應用程式」選項\n\n## 4.2.3 (2020-07-18)\n\n- Add Turkish translation\n- \"Usage monitor\" fix\n\n## 4.2.2 (2020-07-16)\n\n- 解決了從 v4.0.0 起出現的小概率隨機停止執行問題\n- 「使用情況監視器」改進\n- 重新整理字串，任何人都可以參與翻譯\n\n## 4.2.0 (2020-07-12)\n\n- 增加「使用情況監視器」（需要 Android 9 以上和通過 root 啟動的 Shizuku）\n\n  當應用程式使用位置、相機或麥克風時收到提示\n\n## 4.1.1 (2020-07-10)\n\n- 剪貼簿監視：可設定「臨時訪問時限」\n- 剪貼簿監視：修復一個有關「排除的程式」的 UI 問題\n- 修復在 Android 10 以上，從 v4.0.0 起建立的備份可能損壞的問題\n- 正確地回報來自託管裝置管理員模式的錯誤\n- 暫時不使用 AAPT2 的資源優化功能，這可能可以解決部分使用者出現的隨機的設定介面崩潰問題\n\n## 4.1.0 (2020-07-09)\n\n- 剪貼簿監視：增加「視窗位置」和「排除的程式」選項\n- 修復一旦主要程式死掉，「新程式行為」功能就會停止工作\n- 修復權限檢視 UI 重新整理問題\n\n## 4.0.1 (2020-07-05)\n\n- 修復在某些情況下監視服務非正常地啟動\n\n## 4.0.0 (2020-07-04)\n\n用最新技術（部分）重寫。具有更多改進和新功能的全面重寫將在不久的將來出現。\n\n- 新功能：剪貼簿監視（需要 Android 10 以上和通過 root 啟動的 Shizuku）<sup>**〔1〕**</sup>\n- 在 Android 10 及 11 上工作\n- 使用者介面翻新\n- 修復一個有關恢復備份的問題\n- 永遠使用內建的名稱<sup>**〔2〕**</sup>\n- 對於免費版本，移除 Google Ads（轉而推薦我們的其他應用程式）\n- 對於崩潰報告，使用 AppCenter 替代 Firebase Crashlytics（此外，崩潰報告可關閉）\n- 目標 API 30\n- 不再支援 system plugin 模式\n- 不再支援 Android 6.0\n- 不再支援古老的以 LineageOS 為基礎的 ROM 中的詢問模式<sup>**〔3〕**</sup>\n\n<sub><b>〔1〕</b>從監視中排除應用程式的功能將在下個版本中加入</sub>\n<br><sub><b>〔2〕</b>之前，權限的名稱被優先使用。但是隨著 Android 在每個版本間不斷改變權限名稱，權限名稱越來越不準確。</sub>\n<br><sub><b>〔3〕</b>根據使用者報告，一些老舊的三星裝置表現得有這個功能，但是改為「詢問」將會導致系統無法啟動。</sub>\n\n## 3.1.1 (2019-08-03)\n\n- 修復無法編輯模板\n\n## 3.1.0 (2019-08-02)\n\n- 操作系統程式時提供更加明顯的警告\n- 為套用模板對話方塊提供編輯與新增功能\n- 修復使用託管裝置管理員模式時，如果先使用 Island 之後更換為其他也會被判定為正在使用 Island\n\n## 3.0.3 (2019-07-29)\n\n- 小 bug 修复\n- 提供新的包含文档的网站：<https://appops.rikka.app/zh-hans>\n\n## 3.0.2\n\n- 修复托管设备管理员模式坏掉\n- 修复错误的依赖\n\n## 3.0.0\n\n- 托管设备管理员模式：修复当使用 Island 时新应用安装可能不被出发\n- （实验性）托管设备管理员模式：支持多用户（需要 Island 3.8+ 作为设备管理员，2019/7/24 在 Google Play alpha 通道提供)\n- 模板：默认勾选「跳过检查」\n- 模板：改进编辑 UI\n- 如果一个 op 不被原生 Android 包含，显示提示\n- 其他 bug 修复和 UI 改进\n\n## 2.9.9\n\n- 托管设备管理员模式：修复一些与 Island 支持有关的 bug\n- 特权模式：修复总是需要旧式 Shizuku\n- 显示所有工作模式（解释原因如果不支持）\n\n## 2.9.8\n\n- （实验性）托管设备管理员模式支持 Island 应用的「上帝模式」 (com.oasisfeng.island)\n- 特权模式：修复「adb 权限不足」提示从未显示（主要只给 MIUI）\n\n## 2.9.7\n\n- Try to fix \"Code 5\"\n\n## 2.9.5\n\n- Bring back access/reject time for Android Q beta 4 (but as Android Q changed data format and not open sourced yet, no detailed times like Android 9)\n- Fix \"Code 5 debug message: null\" (by upgrading lib from Google :(\n- Minor UI tweaks\n\n## 2.9.4\n\n- Target 29\n- 修 2.9.2 带来的 bug\n\n## 2.9.2\n\n- 修复升级到 2.9.1 后模板丢失\n- 通知语言现在应该完美跟随应用内语言设置\n\n## 2.9.1\n\n- 增加托管设备管理员模式（使用来自支持的设备管理员应用的 API）\n- 修一些 bug\n- 备份包含模板\n\n## 2.8.2\n\n- 修复 root 模式在 Android Q beta 3 上不工作\n- 修复在低版本 Android 上少数功能可能不正常\n- 修复「显示框架应用」选项在 root 模式下不工作\n- 修复 root 模式下 overlay package 们没有被过滤\n\n## 2.8.1\n\n- 在 Android Q beta 3 上能用（但还不能看使用时间）\n- 存储空间选项在 Q beta 3 上无效，这是系统 bug\n- 暂时在 Q beta 3 上隐藏「存储空间沙盒」选项（默认关闭除非应用声明，如何强制开启方法尚不明确）\n- 当未设定默认模板时自动设定第一个（用于拯救从不阅读提示的傻子）\n\n## 2.8.0\n\n- 支持 Android Q 添加的新 op\n- UI 改进\n\n## 2.7.0\n\n- 在 Android 9 上再也不会出现「需要重启应用」\n- 使用特权模式时不再会出现随机错误（需要升级到 Shizuku v3 并强行停止 App Ops）\n\n## 2.6.4\n\n- 更新其他语言的翻译\n- 修复 bug\n\n## 2.6.3\n\n- 更新其他语言的翻译\n- 修复 bug\n\n## 2.6.2\n\n- root 模式支持多用户（实验性）\n- 为根据权限分组的列表加入「已禁用有限」选项\n- 为 Android 9 用户优化控制「在后台运行」时的 UI\n- 修复 bug\n\n## 2.5.10\n\n- 增加为 Android 9 准备的帮助\n- 修复 bug\n\n## 2.5.9\n\n- 修复一个涉及多用户的 bug\n\n## 2.5.8\n\n- 修复 bug\n\n## 2.5.7\n\n- 简化详情界面 UI\n- 修复当一些 op 的 opToSwitch 所对应的权限没有申请时就无法更改那些 op 的 bug\n\n## 2.5.5\n\n- 修复无 root 在 Android 9 上首次使用特权模式的流程\n- 修复编辑中的模板如果进行旋转屏幕等操作会丢失已编辑内容的问题\n- 编辑模板按下返回会询问是否保存\n- 修复在模板名称按下回车会爆炸\n- 默认隐藏未知的 op（对，又是你 MIUI）\n\n## 2.5.3\n\n- 修复一些关于新应用监控的问题\n- 可能修复一些打开就爆炸\n\n## 2.5.2\n\n- 修复在 2.5.0 中系统插件模式无法使用\n- 修复错误信息没有被正确展示\n- 修复在 Android 7.x 上无法正常工作\n- 修复部分 Google Play 用户会出现「您已拥有此物品」的问题\n- 为了让监控新应用安装功能更加可靠，现在它需要运行一个前台服务（仅 Android 8.0 以上），\n  但你可以禁用或将其设定为最低重要程度来避免被打扰\n\n## 2.5.0\n\n- 为 Android 9+ 移除系统插件（因为只有在插件拥有系统签名时才能工作）\n- 简化系统插件安装，只提供 zip 下载\n- 支持 Android 9 添加的 appops 特性（如 MODE_FOREGROUND 和 OP_RUN_ANY_IN_BACKGROUND）\n- 新的 UI\n- 多组模板\n- 解决当长时间后返回， app 无法使用的问题\n\n## 2.4.1\n\n- 更新翻译\n- 尝试修复部分付费用户会被当作未付费用户的问题\n\n## 2.4.0\n\n- 提升 root 模式速度\n\n## 2.3.13\n\n- 尝试修复 root 模式在部分设备无法工作\n- 改变 Android 8+ 上的图标\n\n## 2.3.12\n\n- 尝试修复在恢复备份时可能崩溃\n\n## 2.3.11\n\n- 为所有列表添加全选（长按 -> 菜单里的三个点点 -> 全选）\n- 系统插件模式现在为 Magisk 用户提供 template v1500 的模块\n\n## 2.3.10\n\n- 修复当恢复大量备份时崩溃\n- 修复提示对话框内容不可以滚动的问题\n\n## 2.3.9\n\n- 修了在 Android P DP1 上崩溃（你可能会看到 \"Detect problems with API compatibility\" 的提示，但是对 App Ops 来说不使用隐藏 API 是不可能的）\n\n## 2.3.8\n\n- 增加「显示全部模式」选项（不懂是什么就别打开）\n\n## 2.3.7\n\n- _始终显示权限（操作）_ 将会排除一些绝对不可能的情况\n- 增加被安装到外部存储的错误提示（都 8012 了怎么还有这种人）\n- 更新葡萄牙语（巴西）翻译\n- 移除一些未使用资源\n- 修复创建备份坏掉\n\n## 2.3.6\n\n- 修了总是提示 Google play 不可用\n- 增加一个显示全部支持的权限（操作）的列表\n- 在应用列表中标记系统应用\n- 增加 _始终显示的权限（操作）_ 列表，每个应用都会被当作可能使用选中的权限\n- 调整设置 UI\n\n## 2.3.5\n\n- 修复备份预览坏掉\n- 增加本地网络（特权模式需要使用）受限时的提示\n- 处理一些未捕获的错误\n\n## 2.3.4\n\n- 修复 root 模式下重置无效的问题（真·上古 bug）\n- 修复从应用列表重置或应用模板不会刷新 UI 的问题\n\n## 2.3.3\n\n- 修了两个上古 bug\n\n## 2.3.2\n\n- 修了 2.3.0 留下的 bug\n- 异步读取其他信息（比如已修改的项数），因此现在读取应用列表速度会非常快\n\n## 2.3.0\n\n- 为应用列表增加已修改的项数\n- 极大加速 root 模式下获取 appops 配置的速度\n- Oreo 风格的应用详情视图\n- 支持 Android 8.1 的亮色导航栏\n- 修改一些令人疑惑的 UI\n- (免费用户) 因为 Google 将在 2018 年 3 月后移除快捷原生广告，所以换回旧的横幅广告\n- 修复一些和多用户有关的问题\n- (付费用户) 修复在应用安装后，即使备份存在且打开了恢复备份，只要模板存在就被套用的问题\n- 因为一些原因，移除对旧的 Shizuku （特权模式）的支持\n\n## 2.2.6\n- 修复 Shizuku Manager 比 App Ops 安装晚会无法使用的问题\n\n## 2.2.5\n- 为新应用监控添加开机启动\n- 添加 Portuguese (Brazil) 语言\n\n## 2.2.4\n- 增加针对 adb 有读取 appops 配置但没有写入权限时的提示（比如 MIUI MIUI 和 MIUI）\n- 使用新的 build tool 来避免一个只在部分低版本第三方 ROM 上出现的可怕的问题 ([看这里](https://issuetracker.google.com/issues/64434571))\n\n## 2.2.3\n\n- 修复_特权模式_使用旧版 _Shizuku Manager_ 可能会崩溃的问题\n- 从通知套用模板时不再检查是否有 `RUN_IN_BACKGROUND`\n- 修复切换工作模式时设置崩溃\n\n## 2.2.2\n\n- 修复选择_特权模式_时没有安装 _Shizuku Manager_ 会崩溃\n\n## 2.2.1\n\n- 增加指定界面语言的功能\n- 更新翻译\n- 通过反射 `PackageInfo#overlayTarget` 的方式过滤 overlay apps\n- 修了新应用通知上的按钮在部分设备上可能不能用的问题\n- 套用模板时不再检查是否有 `RUN_IN_BACKGROUND`\n\n## 2.2.0\n\n- 修复套用模板或恢复备份后通知不能消除的问题\n- 重新规划主菜单项目\n- 将「显示框架应用」移至主菜单\n- 增加「根据更新时间排序」，「根据安装时间排序」\n- 实验室增加 \"Show target 0 apps\" (为了过滤掉 substratum overlay)\n- 重构设置向导，同时增加更多说明\n- 调整设置 UI\n- 修复通知不能显示自适应图标 (8.0+)\n\n## 2.1.12 (beta)\n\n- 在获取应用列表是请求更少数据\n\n> 解决部分设备上只能获得部分应用（甚至出现 \"Package Manager has died\"）的问题。\n\n> 会加快列表刷新速度。\n\n> 但没有那些数据，we have to remove \"show apps without icon\" option because we can't know\nif the app have a entrance, and \"run in background\" (Android 7.0+) will always shown because we can't\nspeculated if the app have background behavior.\n\n- （特权模式）让 Shizuku manager 展示服务没有运行\n- 新的版本号明明规则\n- 适配 Font Provider API v8\n\n## 2.1.11\n\n- Fix system plugin broadcast does not work\n- Fix notification didn't show when plugin stopped\n- Improve Settings UI for RTL language\n- 引入 Shizuku v2 (特权模式)，加入 Shizuku Manager 的测试来尝试\n- Font Provider 默认开启\n\n## 2.1.10\n\n- 当系统插件权限不足时给用户更友好的提示\n- 再次修复使用系统插件时有时需要手动刷新\n- 更新 Font Provider 依赖到 1.3.2，应该没问题了\n- 增加更多帮助\n- 修了一些对话框的按钮颜色\n\n## 2.1.9\n\n- Fix NPE in WorkService\n- Move system plugin download to GitHub release\n- Fix crash when open help in runtime permission tip dialog\n- Notify list refresh when system plugin connected\n- Update translation\n- Add translator's name to about\n\n## 2.1.2 - 2.1.8\n\n- 修复无法创建备份文件\n- 实验室（包含未确定或实验性功能）功能入口现在总是显示\n- Provide fastScroll drawable from AOSP to avoid crash on some devices\n- Update help\n- Fix test link in pro version\n- 100% fix theme and night mode, it should work perfectly now\n- Update adaptive icon for Android O\n- Add tip of Runtime Permissions when entering app target 23+\n- 改进的主题\n- 提供一个新的选项来使用 \"Noto Sans CJK Medium\" 替换 \"sans-serif-medium\" 字体（需要配合 Font Provider 应用使用）\n- Add tip for users can't use system plugin on Android O\n\n## 2.1.1\n\n- 增强的备份功能 (PRO)\n  - 当用户改变权限设置后，设置会被自动保存至数据库。当应用在卸载后再次安装或是被使用设备管理器的冻结类应用（如[冰箱](https://play.google.com/store/apps/details?id=com.catchingnow.icebox)的免 root模式）禁用后重新启用后可以选择恢复。\n- 增加详细的更新日志\n- 新的更详细的帮助"
  },
  {
    "path": "appops/zh-hant/download.md",
    "content": "# 下載\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com/apk/rikka.appops)\n\n[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)"
  },
  {
    "path": "appops/zh-hant/guide/README.md",
    "content": "# 瞭解 App Ops\n\n簡而言之，**App Ops** 是一個修改 **Android 系統中的 \"appops\" 設定** 的程式。\n\n## 什麼是 Android 系統中的 \"appops\"\n\n在 Android 系統中存在一個叫做 \"appops\" 的系統服務，該服務定義了一系列的「程式操作」(application operation, op)。其中部分「程式操作」與「權限」對應（如 `OP_CAMERA` 與「相機權限」），其餘則對應單獨的功能（如 `OP_READ_CLIPBOARD` 與讀取剪貼簿，但並不存在「讀取剪貼簿權限」）。\n\n原生 Android 系統使用 appops 來追蹤權限使用，appops 也部分被用於權限控制。每個程式都有自己的 \"appops\" 設定，當程式需要執行某些操作時，系統在檢查權限的同時也會檢查 \"appops\" 設定。如果沒有授予權限，程式在執行操作時將會收到錯誤。但不同的是，如果 \"appops\" 設為忽略<sup>**〔1〕**</sup>，程式不會收到錯誤只會收到空白資料<sup>**〔2〕**</sup>。\n\n但是原生 Android 系統並沒有提供修改 \"appops\" 設定的使用者介面。\n\n<sub>**〔1〕** App Ops 程式中實際將「忽略」顯示為「拒絕」</sub>\n<br><sub>**〔2〕** 實際行為取決於系統，程式也可檢查 \"appops\" 是否被拒絕</sub>\n\n## 什麼是 App Ops 程式\n\nApp Ops 程式的核心功能是修改系統 \"appops\" 設定，可以在某種意義上實現權限管理。App Ops 程式還做出很多努力簡化許多技術細節，讓使用更加簡單。\n\n## 用語宣告\n\n### 「權限」\n\nApp Ops 實際修改的是「程式操作」而非「權限」，但為了降低難度將其稱為「權限」。App Ops 程式**不可以直接操作「權限」**，請不要誤解。\n\n::: tip\n幫助中的其他地方仍稱其為「權限」。\n:::\n\n## App Ops 的限制\n\n### 可以修改的權限取決於系統\n\nApp Ops 所能修改的權限**只取決於你的系統**，所以别再問「為什麼沒有 XXX 權限」了。\n\n通常，系統版本越高，能修改的內容越多（廠商或自定義 ROM 可能會新增自己的權限）。所有你的系統支援的權限可以在 設定 - 行為 - 全部權限 中看到。\n\n### 程式仍可以獲知沒有權限\n\n程式可以檢查返回資料是否為空白，或是直接檢查 \"appops\" 是否被允許。只是很少有程式這麼做。\n"
  },
  {
    "path": "appops/zh-hant/guide/faq/how_to_reset.md",
    "content": "# 如何重置全部設定？\n\n1. 切換到應用列表模式\n2. 長按或點選左側應用圖示進入多選模式\n3. 右上方三點選單 - 全選\n4. 選擇「重置」"
  },
  {
    "path": "appops/zh-hant/guide/faq/purchase.md",
    "content": "# 購買或恢復問題\n\n## Google Play 恢復問題\n\n大部分情況下，按照點擊購買後出現的提示文字處理即可，如果仍不能解決問題，請發送郵件給我們。"
  },
  {
    "path": "appops/zh-hant/guide/technical/run_in_background.md",
    "content": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`（在後臺執行）\n\n在 App Ops 應用中看到的「在後臺執行」實際是指 `RUN_IN_BACKGROUND`（Android 7 起增加）和 `RUN_ANY_IN_BACKGROUND`（Android 9 起增加）這兩個 op。在不同的系統版本上，改變這些 op 會有不同的行為。\n\n這篇文章將會說明在 Android 9 上修改 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 對應用行為的影響。\n\n## App Ops 應用所做的特殊處理\n\n為了應對 Android 9 新增加的 `RUN_ANY_IN_BACKGROUND`，App Ops v2.6.0 以前採取這樣的策略：直接將 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 視為同一個，即只會看到一個「在後臺執行」選項，修改時會同時修改這兩個。但部分特殊情況下，同時設定兩個會造成限制過於嚴格的問題，因此從 v2.6.0 起可以自行選擇限制哪一個。\n\n## `RUN_IN_BACKGROUND`\n\n> 文章尚未完成，更多資訊將在以後補充\n\n所有 target API 在 26 及以上的應用會受到此限制。\n\n參考以下文章：\n\nhttps://developer.android.com/about/versions/oreo/background\n\n## `RUN_ANY_IN_BACKGROUND`\n\n> 文章尚未完成，更多資訊將在以後補充\n\n參考以下文章：\n\nhttps://developer.android.com/about/versions/pie/power#battery-saver\n\nhttps://developer.android.com/topic/performance/power/power-details\n\n部分涉及的 commit：\n\nhttps://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18\n\nhttps://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16"
  },
  {
    "path": "appops/zh-hant/guide/technical/system_behaviors.md",
    "content": "# 不同 Android 版本下的不同\n\n每個 op 都有兩種 mode，分別為 `package mode` 和 `uid mode`。`uid mode` **有更高優先順序**，即只有當 `uid mode` 為預設值時才會使用 `package mode`。\n\n以下表格展示了從系統修改權限設定時，`uid mode` 會被如何設定。\n\n::: details 表格\n<p>\n\n星號（*）表示相對之前的系統放生變化。\n\n#### Android 6 - Android 9\n| 系統設定頁面 | uid mode                                |\n|--------------|-----------------------------------------|\n| 允許         | allow                                   |\n| 拒絕         | ignore（只對 target 23 以下的應用程式設定） |\n| （尚未設定） | (allow)                                 |\n\n#### Android 10\n\n| 系統設定頁面       | uid mode   |\n|--------------------|------------|\n| 僅在使用期間允許 * | foreground |\n| 允許               | allow      |\n| 拒絕 *             | ignore     |\n| （尚未設定）       | (allow)    |\n\n#### Android 11\n\n| 系統設定頁面       | uid mode   |\n|--------------------|------------|\n| 每次都詢問 *       | ignore     |\n| 僅在使用期間允許 * | foreground |\n| 允許               | allow      |\n| 拒絕               | ignore     |\n| （尚未設定）*      | ignore     |\n\n#### Android 11 中的其他行為\n\n* 設定 `package mode` 無效\n* 設定 `uid mode` 時，若設定值不符合執行時權限狀態則無效\n* 在特定的情況下（比如安裝應用程式後），系統將重設**全部應用程式**的 appops 設定到與執行時權限符合的狀態\n\n:::\n\n### 舊版本 App Ops 沒做對\n\n舊版本的 App Ops（v5.0.0 以前）只會讀取和修改 `package mode`，這顯然是不對的。\n\n在 Android 9 及之前，對 target 23 以下的應用程式在 App Ops 中設定「允許」是無效的；在 Android 10，一旦使用者在系統中設定「拒絕」或「僅在使用時允許」，則在 App Ops 中的設定永遠無法生效（因為此時系統設定的 `uid mode` 被優先使用）。\n\n由於從低版本升級時系統的權限設定是被保留的，這個巨大的問題在 Android 10 釋出的一年後才慢慢地暴露出來。\n\n### 新版本（v5.0.0）App Ops 所做出的變化\n\n除了完全跟隨系統行為以外別無選擇。\n\n另外，因為 Android 11 會重置 appops 設定（所有「執行時權限允許，ops 忽略」會被重設為「執行時權限拒絕」），所以除了在系統之後再次重設以外別無選擇。\n\n### 新版本（v5.0.0）App Ops 需要更多能力\n\n想要正確跟隨系統行為，App Ops 必須具備取得和設定 `runtime permission`，`permission flags`，`appops` 的能力。但是，並不是所有工作模式都能做到。\n\n|                    | Shizuku 模式 | 託管裝置管理員模式           | root 模式（已被移除） |\n|--------------------|--------------|------------------------------|-----------------------|\n| appops             | ✔️            | ✔️                            | ✔️                     |\n| runtime permission | ✔️            | 僅可設定<sup>**〔1〕**</sup> | ❌                     |\n| permission flags   | ✔️            | ❌                            | ❌                     |\n\n<sub><b>〔1〕</b>需要 Island v5.0+ 或其他具有 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) v3 支援的管理員程式</sub>\n\n#### 「託管裝置管理員模式」的缺陷\n\n* 「無法確認」\n* 無法備份全部設定\n* 在 Android 11，無法設定新增的「每次都詢問」（需要「設定 permission flags」）\n\n::: details 技術資訊\n\n被設為 `profile owner` 或 `device owner` 的管理員程式享有一些特權，但是隻有它們自身可以使用。因此，不同的管理員程式提供了不同的 API，使其他應用程式得以「借用」其特權。\n\n* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)\n* [Delegation API](https://island.oasisfeng.com/api)\n\n只有提供 Delegation API 的 Island v5.0+ 支援「設定 runtime permission」。\n\n對於「無法確認」，舉個例子，在 Android 10 中：\n\n|              | appops     | runtime permission | permission flags |\n|--------------|------------|--------------------|------------------|\n| 忽略         | ignore     | true               |                  |\n| 拒絕         | （任何值） | false              | 任意 \"FIXED\"     |\n| （尚未設定） | （任何值） | false              | 無 \"FIXED\"       |\n\n只看 appops 設定顯然不夠。\n\n:::\n\n#### 為什麼必須移除「root 模式」\n\n純 root（執行指令）的能力十分有限，沒有可以修改 permission flags 的指令。想要正確修改 runtime permission 必須保證 permission flags 也被正確地修改（裝置管理員所使用的更高層級的 Java API 不需要考慮這個問題）。\n\n因此，root 模式已被移除。\n\n::: details 技術資訊\n\n很多人會認為 root 無所不能，但實際上 root 只提供了一個 `uid 0` 的 shell。想要進入 Android 世界（直接使用 Java API），通過 `app_process` 執行 dex 幾乎是唯一選擇。\n\n「root 模式」的替代——「Shizuku 模式」使用 Shizuku（[GitHub](https://github.com/RikkaApps/Shizuku)）做這一部分的工作。如果不使用 Shizuku，則仍然需要執行類似 Shizuku 的東西，這樣做是沒有意義的，並且也將帶來無意義的資源使用。\n\n:::"
  },
  {
    "path": "appops/zh-hant/guide/working_mode/dpm.md",
    "content": "# 託管裝置管理員模式\n\n::: warning 警告\n\n從 6.0.0 起，此工作模式不再支援。若要繼續使用此工作模式，請[下載 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/download/files/appops-v5.5.6.r1453.f44c5855.apk)。\n\n:::\n\n## 需求及特性\n\n* 需要 Android 9+\n* 需要安裝其他應用程式，並使用 adb 將其設為 Device owner\n* 是否支援多使用者取決於 Device owner 應用程式\n\n## 背景\n\n託管裝置管理員模式是 App Ops 從 v2.9.0 開始加入的新的工作模式。從 Android 9 開始，裝置管理員開始可以修改 appops 設定，但系統限制一臺裝置上僅能設定一個程式為裝置管理員。因此 App Ops 使用由其他裝置管理員程式提供的 API。\n\n從 v2.9.0 起支援使用 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) 的裝置管理員程式。\n\n從 v2.9.8 起支援另一種[由 Island 提供的 API](https://island.oasisfeng.com/api)。\n\n## 免責聲明\n\n你需要安裝的裝置管理員程式都不是由我們開發。\n\n::: warning\n裝置管理員在 Samsung 裝置及很多來自中國大陸地區廠商的裝置上或多或少存在一些問題，請務必仔細閱讀來自裝置管理員程式提供的幫助，如果你無法接受可能的問題，請不要使用。\n:::\n\n::: danger\nSamsung 裝置在使用裝置管理員後可能造成無法挽回的結果（參閱 [來自 冰箱 IceBox 的文件](https://iceboxdoc.catchingnow.com/Device%20Owner%20%E4%B8%89%E6%98%9F%E7%89%B9%E5%88%AB%E8%AF%B4%E6%98%8E)），請務必謹慎。\n:::\n\n## 如何使用\n\n設定過程需要連線電腦使用 adb，但只需要進行一次設定。\n\n### 1. 安裝及設定裝置管理員程式\n\n#### 冰箱 IceBox\n\n1. 下載 [Google Play](https://play.google.com/store/apps/details?id=com.catchingnow.icebox) 或 [Coolapk](https://www.coolapk.com/apk/com.catchingnow.icebox)\n2. 參閱 [幫助](https://iceboxdoc.catchingnow.com/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE) 為其設定裝置管理員模式\n\n#### 小黑屋\n\n1. 下載 [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) 或 [Coolapk](https://www.coolapk.com/apk/web1n.stopapp)\n2. 參閱 [幫助](https://github.com/web1n/Stopapp-Docs/blob/master/Device%20Owner%20%EF%BC%88%E5%85%8D%20root%EF%BC%89%E6%A8%A1%E5%BC%8F%E8%AE%BE%E7%BD%AE.md)（僅提供簡體中文） 為其設定裝置管理員模式\n\n#### Island\n\n1. 下載 [Google Play](https://play.google.com/store/apps/details?id=com.oasisfeng.island) 或 [Coolapk](https://www.coolapk.com/apk/com.oasisfeng.island)\n2. 參閱 [幫助](https://island.oasisfeng.com/setup.html) 為其設定裝置管理員模式（Island 稱其為「上帝模式」）\n\n### 2. 授予權限\n\n在 App Ops「設定」-「工作模式」中選擇「託管裝置管理員模式」後返回程式列表應該會彈出來自裝置管理員程式的授權對話方塊，請在勾選「修改 app ops」後確認。\n\n接著，你還需要使用使用 adb 授予 App Ops 「獲取 app ops」 權限。使用以下的指令：\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS\n```\n\n注意，如果你將 App Ops 程式安裝到其他使用者，需要將其中 `--user 0` 的 `0` 替換為其他使用者的 id（使用 `adb shell pm list users` 獲得的 `UserInfo{0:Owner:13} running` 的結果中的 `0` 即為使用者 id）。\n\n### 3. 授予多使用者許可權\n\n對於多使用者支援，你還需要執行下面的指令來讓 App Ops 可以部分訪問其他使用者：\n\n```\nadb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS\n```\n\n::: tip\n目前只有 Island 3.8+ 支援多使用者\n:::\n\n### 4. 遇到問題？\n\n* 使用 Island 時出現 `Cannot request permission without a restrictions provider registered`\n\n  清除 Island 的快取（應用資訊 -> 儲存 -> 清除快取），後重新啟動 Island。"
  },
  {
    "path": "appops/zh-hant/guide/working_mode/shizuku.md",
    "content": "# Shizuku 模式\n\n## 需求及特性\n\n* 需要安裝 Shizuku 應用程式並通過 adb 或 root 啟動 Shizuku 服務\n* 支援多使用者\n\n::: tip\n如果使用 adb，每次開機都需要使用 adb 進行啟動 Shizuku 的步驟（**但 appops 設定總是生效**）\n:::\n\n## 背景\n\nShizuku 是一個免費且[開源](https://github.com/RikkaApps/Shizuku)的類似於框架的應用程式。它旨在服務多個需要 root 或 adb 的應用程式。Shizuku 在對效能的影響最小的情況下，極大地提高了使用 Shizuku 的應用程式的效能和可靠性。 此外，Shizuku 還為開發人員提供了極大的便利。\n\n> 有關 Shizuku 的資訊，以及為什麼要獨立出一個應用程式，請檢視 [shizuku.rikka.app](https://shizuku.rikka.app/zh-hant)。"
  },
  {
    "path": "assets/SourceCodePro-BDC.css",
    "content": "@font-face {\n    font-family: 'Source Code Pro BDC';\n    src: local('Source Code Pro'), local('SourceCodePro-Regular.ttf'), url('../fonts/SourceCodePro-BDC-Regular.woff2') format('woff2');\n    font-weight: 400;\n    font-display: swap;\n    font-style: normal;\n\tunicode-range: U+2500-259F;\n}"
  },
  {
    "path": "package.json",
    "content": "{\n  \"dependencies\": {\n    \"moment\": \"^2.29.1\",\n    \"vuepress\": \"^1.8.2\",\n    \"vuepress-plugin-clean-urls\": \"^1.1.2\",\n    \"vuepress-plugin-sitemap\": \"^2.3.1\"\n  },\n  \"scripts\": {\n    \"appops:dev\": \"vuepress dev appops\",\n    \"appops:build\": \"vuepress build appops\",\n    \"shizuku:dev\": \"vuepress dev shizuku\",\n    \"shizuku:build\": \"vuepress build shizuku\",\n    \"sr:dev\": \"vuepress dev storage_redirect\",\n    \"sr:build\": \"vuepress build storage_redirect\",\n    \"www:dev\": \"vuepress dev www\",\n    \"www:build\": \"vuepress build www\"\n  }\n}\n"
  },
  {
    "path": "shizuku/.gitignore",
    "content": "/.vuepress/dist"
  },
  {
    "path": "shizuku/.vuepress/config.js",
    "content": "const moment = require('moment')\nconst langMap = {\n  \"zh-Hans\": \"zh-cn\",\n  \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}\n\nmodule.exports = {\n  base: '/',\n  title: 'Shizuku',\n  head: [\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]\n  ],\n  locales: {\n    '/': {\n      lang: 'en',\n      description: 'Let your app use system APIs directly'\n    },\n    '/zh-hans/': {\n      lang: 'zh-Hans',\n      description: '让你的应用直接使用系统 API'\n    },\n    '/zh-hant/': {\n      lang: 'zh-Hant',\n      description: '讓你的應用程式直接使用系統 API'\n    }\n  },\n  themeConfig: {\n    locales: {\n      '/': {\n        selectText: 'Languages',\n        label: 'English',\n        serviceWorker: {\n          updatePopup: {\n            message: \"New content is available.\",\n            buttonText: \"Refresh\"\n          }\n        },\n        sidebar: {\n        },\n        nav: getNavbar('/', 'Introduction', 'User manual', 'Download', 'Developer guide'),\n        lastUpdated: 'Last Updated'\n      }\n      ,\n      '/zh-hans/': {\n        selectText: '语言',\n        label: '简体中文',\n        editLinkText: '在 GitHub 上编辑此页',\n        serviceWorker: {\n          updatePopup: {\n            message: \"发现新内容可用.\",\n            buttonText: \"刷新\"\n          }\n        },\n        sidebar: {\n        },\n        nav: getNavbar('/zh-hans/', '简介', '用户手册', '下载', '开发者指南'),\n        lastUpdated: '最后更新'\n      },\n      '/zh-hant/': {\n        selectText: '語言',\n        label: '繁體中文',\n        editLinkText: '在 GitHub 上編輯此頁',\n        serviceWorker: {\n          updatePopup: {\n            message: \"發現新內容可用.\",\n            buttonText: \"重新整理\"\n          }\n        },\n        sidebar: {\n        },\n        nav: getNavbar('/zh-hant/', '簡介', '使用者手冊', '下載', '開發者指南'),\n        lastUpdated: '最後更新'\n      }\n    },\n    displayAllHeaders: true,\n    sidebarDepth: 2,\n    serviceWorker: {\n      updatePopup: true\n    },\n    repo: 'https://github.com/RikkaApps/Shizuku',\n    docsRepo: 'https://github.com/RikkaApps/websites',\n    docsDir: 'shizuku',\n    editLinks: true\n  },\n  plugins: [\n    [\n      'sitemap',\n      {\n        hostname: 'https://shizuku.rikka.app',\n        exclude: ['/404.html'],\n        dateFormatter: (time) => {\n          timestampCache[time]\n        }\n      }\n    ],\n    [\n      'clean-urls',\n      {\n        normalSuffix: '/',\n        indexSuffix: '/',\n        notFoundPath: '/404.html'\n      }\n    ],\n    [\n      '@vuepress/last-updated',\n      {\n        transformer: (timestamp, lang) => {\n          var original = timestamp\n\n          moment.locale(langMap[lang])\n          var localized = moment(original).format('lll')\n          \n          moment.locale('en')\n          var iso = moment(original).toISOString()\n          timestampCache[localized] = iso\n\n          return localized\n        }\n      }\n    ]\n  ]\n}\n\nfunction getNavbar(prefix, introduction, guide, download, dev) {\n  return [\n    { text: introduction, link: `${prefix}introduction` },\n    { text: guide, link: `${prefix}guide/setup.html` },\n    { text: dev, link: `https://github.com/RikkaApps/Shizuku/blob/master/README.md` },\n    { text: download, link: `${prefix}download.html` },\n  ]\n}"
  },
  {
    "path": "shizuku/.vuepress/public/icon/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><square150x150logo src=\"/ms-icon-150x150.png\"/><square310x310logo src=\"/ms-icon-310x310.png\"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>"
  },
  {
    "path": "shizuku/.vuepress/public/icon/manifest.json",
    "content": "{\n \"name\": \"App\",\n \"icons\": [\n  {\n   \"src\": \"\\/android-icon-36x36.png\",\n   \"sizes\": \"36x36\",\n   \"type\": \"image\\/png\",\n   \"density\": \"0.75\"\n  },\n  {\n   \"src\": \"\\/android-icon-48x48.png\",\n   \"sizes\": \"48x48\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-72x72.png\",\n   \"sizes\": \"72x72\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.5\"\n  },\n  {\n   \"src\": \"\\/android-icon-96x96.png\",\n   \"sizes\": \"96x96\",\n   \"type\": \"image\\/png\",\n   \"density\": \"2.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-144x144.png\",\n   \"sizes\": \"144x144\",\n   \"type\": \"image\\/png\",\n   \"density\": \"3.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-192x192.png\",\n   \"sizes\": \"192x192\",\n   \"type\": \"image\\/png\",\n   \"density\": \"4.0\"\n  }\n ]\n}"
  },
  {
    "path": "shizuku/.vuepress/theme/index.js",
    "content": "module.exports = {\n  extend: '@vuepress/theme-default'\n}"
  },
  {
    "path": "shizuku/.vuepress/theme/layouts/Layout.vue",
    "content": "<template>\n  <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport default {\n  components: {\n    ParentLayout\n  }\n}\n</script>"
  },
  {
    "path": "shizuku/.vuepress/theme/styles/index.styl",
    "content": "code\n  overflow: auto\n  word-wrap:break-word\n\nbody\n  font-family Roboto, sans-serif\n\nbody:lang(zh-hans)\n  font-family Roboto, 'Noto Sans SC', sans-serif\n\nbody:lang(zh-hant)\n  font-family Roboto, 'Noto Sans TC', sans-serif\n"
  },
  {
    "path": "shizuku/.vuepress/theme/styles/palette.styl",
    "content": "$accentColor = #3949ab\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
  },
  {
    "path": "shizuku/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Learn more\nactionLink: /introduction.html\nfeatures:\n- title: Use system APIs elegantly\n  details: Forget about root shell, you can use APIs with higher privileges \"directly\". Also, Shizuku is significantly faster than shell.\n- title: Supports adb usage\n  details: If your \"root required app\" only needs adb permission, you can easily expand the audience by using Shizuku.\n- title: Save your time\n  details: Shizuku has detailed documentation to guide users. Only you need to do is to let the users install Shizuku.\nfooter: Copyright © 2019 RikkaApps\n---\n\n### As Easy as you are a system app\n\n```java\nprivate static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(\n    new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(\"package\")));\n\npublic static void grantRuntimePermission(String packageName, String permissionName, int userId) {\n    try {\n        PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);\n    } catch (RemoteException tr) {\n        throw new RuntimeException(tr.getMessage(), tr);\n    }\n}\n```\n\n::: tip\n\nThere a few more steps to do, like checking permission or if Shizuku is running.\n:::\n"
  },
  {
    "path": "shizuku/download.md",
    "content": "# Download\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)\n\n[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)\n"
  },
  {
    "path": "shizuku/guide/setup.md",
    "content": "# User manual\n\n[[toc]]\n\n## Start Shizuku\n\nShizuku supports startup in the following three ways.\n\n::: tip If you are using GrapheneOS\n\nSystem settings - \"Security\" - \"Secure app spawning\" may need to be disabled.\n\n[Source](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)\n\n:::\n\n### Start with root\n\nFor rooted devices, just start directly.\n\n### Start via wireless debugging\n\nStarting with wireless debugging works on Android 11 or above. This startup method does not require a connection to a computer. Due to system limitations, the startup steps need to be performed again after each reboot.\n\n#### Enable Wireless debugging\n\n1. Search the web for how to enable \"Developer options\" for your device model\n2. Enable \"Developer options\" and \"USB Debugging\"<br><br><img :src=\"$withBase('/images/enable_dev_options.png')\" style=\"max-width:320px;width:100%\">\n3. Enter \"Wireless debugging\"<br><br><img :src=\"$withBase('/images/enter_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n4. Enable \"Wireless debugging\"<br><br><img :src=\"$withBase('/images/enable_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n   \n#### Pairing (only needs once)\n\n1. Start pairing in Shizuku<br><img :src=\"$withBase('/images/start_paring_from_shizuku.png')\" style=\"max-width:320px;width:100%\">\n2. [Enable Wireless debugging](#enable-wireless-debugging)\n3. Tap \"Pair device with pairing code\" in \"Wireless debugging\"<br><img :src=\"$withBase('/images/start_pairing.png')\" style=\"max-width:320px;width:100%\">\n4. Enter pairing code in Shizuku's notificaiton<br><img :src=\"$withBase('/images/enter_pairing_code.png')\" style=\"max-width:320px;width:100%\">\n\n#### Start Shizuku\n\n<img :src=\"$withBase('/images/start_shizuku.png')\" style=\"max-width:320px;width:100%\">\n\nIf it does not start, try disabling and enabling wireless debugging.\n\n### Start by connecting to a computer\n\nThis boot method works on unrooted devices running Android 10 and below. Unfortunately, this startup method requires a computer. Due to system limitations, the boot steps need to be performed again after each reboot.\n\n#### What is `adb`?\n\nAndroid Debug Bridge (`adb`) is a versatile command-line tool that lets you communicate with a device. The adb command facilitates a variety of device actions, such as installing and debugging apps, and it provides access to a Unix shell that you Can use to run a variety of commands on a device.\n\nSee [Android Developer](https://developer.android.com/studio/command-line/adb) for more information.\n\n#### Install `adb`\n\n1. Download \"SDK Platform Tools\" provided by Google and extract it to any folder\n\n   * [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)\n   * [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)\n   * [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)\n\n2. Open the folder, right click to select\n\n   * Windows 10: Open PowerShell windows here (**hold down Shift to show this option**)\n   * Windows 7: Open command window here (**hold down Shift to show this option**)\n   * Mac or Linux: Open Terminal\n\n3. Enter `adb`, if success, you can see a long list of content instead of the prompt not finding adb.\n\n::: tip\n1. Please do not close this window. The \"terminal\" mentioned later refers to this window (if you closed the window, please go back to step 2)\n2. If you use PowerShell or Linux/Mac, all `adb` should be replaced with `./adb`\n:::\n\n#### Setting `adb`\n\nTo use `adb` you first need to turn on USB debugging on your device, usually by following these steps:\n\n1. Open system Settings and go to About.\n2. Click \"Build number\" quickly for several times, you can see a message similar to \"You are a developer\".\n3. At this point, you should able to find \"Developer Options\" in Settings,  enable \"USB Debugging\".\n4. Connect the device to the computer and type `adb devices` in the terminal.\n5. At this time, the dialog \"Allow debugging\" will appear on the device, check \"Always allow\" and confirm.\n6. Enter `adb devices` again in the terminal. If there is no problem, you will see something like the following.\n\n   ```\n   List of devices attached\n   XXX      device\n   ```\n\n::: tip\nThe steps for enabling Developer Options on different devices may vary, please search for yourself.\n:::\n\n#### Start Shizuku\n\nCopy the command and paste into the terminal. If there is no problem, you will see that Shizuku has started successfully in Shizuku app.\n\n\n::: details Command for Shizuku v11.2.0+\n\n```\nadb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh\n```\n:::\n\n## FAQ\n\nMany manufacturers have made modifications to the Android system that prevent Shizuku from working properly.\n\n### Start via wireless debugging: keeps showing \"Searching for pairing service\"\n\nPlease allow Shizuku to run in the background.\n\nSearching for pairing service requires access to the local network, and many manufacturers disable network access for apps as soon as they become invisible. You can search the web for how to allow apps to run in the background on your device.\n\n### Start via wireless debugging: immediately fail after tapping \"Enter pairing code\"\n\n#### MIUI (Xiaomi, POCO)\n\nSwitch notification style to \"Android\" from \"Notification\" - \"Notification shade\" in system settings.\n\n### Start via wireless debugging/Start by connecting to a computer: the permission of adb is limited\n\n#### MIUI (Xiaomi, POCO)\n\nEnable \"USB debugging (Security options)\" in \"Developer options\". **Note that this is a separate option from \"USB debugging\".**\n\n#### ColorOS (OPPO & OnePlus)\n\nDisable \"Permission monitoring\" in \"Developer options\".\n\n#### Flyme (Meizu)\n\nDisable \"Flyme payment protection\" in \"Developer options\".\n\n### Start via wireless debugging/Start by connecting to a computer: Shizuku randomly stops\n\n#### All devices\n\n- Make sure Shizuku can run in the background.\n- Do not disable \"USB debugging\" and \"Developer options\".\n- Change the USB usage mode to \"Charge only\" in the \"Developer options\".\n  \n  On Android 8, the option is \"Select USB configuration\" - \"Charge only\".\n  \n  On Android 9+, the option is \"Default USB configuration\" - \"No data transfer\".\n\n- (Android 11+) Enable \"Disable adb authorization timeout\" option\n\n#### EMUI (Huawei)\n\nEnable \"Allow ADB debugging options in 'Charge only' mode\" in \"Developer options\".\n\n#### MIUI (Xiaomi, POCO)\n\nDo not use the scan feature in MIUI's \"Security\" app, since it will disable \"Developer options\".\n\n#### Sony\n\nDon't click the dialog shows after connecting the USB, because it will change USB usage mode.\n\n### Start via root: cannot start on boot\n\nPlease allow Shizuku to run in the background.\n"
  },
  {
    "path": "shizuku/introduction.md",
    "content": "# Introduction\n\nShizuku can help normal apps uses system APIs directly with adb/root privileges with a Java process started with app_process.\n\nThe name Shizuku comes from [a character](https://danbooru.donmai.us/posts/3553474).\n\n## Why was Shizuku born?\n\nThe birth of Shizuku has two main purposes.\n\n1. Provide a convenient way to use system APIs\n2. Convenient for the development of some apps that only requires adb permissions\n\n## Shizuku vs. \"Old school\" method\n\n### \"Old school\" method\n\nFor example, to enable/disable components, some apps that require root privileges execute `pm disable` directly in `su`.\n\n1. Execute `su`\n2. Execute `pm disable`\n3. (pre-Pie) Start the Java process with app_process ([see here](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm))\n4. (Pie+) Execute the native program `cmd` ([see here](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/))\n5. Process the parameters, interact with the system server through the binder, and process the result to output the text result.\n\nEach of the \"Execute\" means a new process creation, su internally uses sockets to interact with the su daemon, and a lot of time and performance are consumed in such process. (Some poorly designed app will even execute `su` **every time** for each command)\n\nThe disadvantages of this type of method are:\n\n1. **Extremely slow**\n2. Need to process the text to get the result\n3. Features are subject to available commands\n4. Even if adb has sufficient permissions, the app requires root privileges to run\n\n### Shizuku method\n\nThe Shizuku app will direct the user to run a process (Shizuku service process) using root or adb.\n\n1. When the app process starts, the Shizuku service process sends the binder to the app process.\n2. The app interacts with the Shizuku service through the binder, and the Shizuku service process interacts with the system server through the binder.\n\nThe advantages of Shizuku are:\n\n1. Minimal extra time and performance consumption\n2. It is almost identical to the direct invocation API experience (app developers only need to add a small amount of code)\n"
  },
  {
    "path": "shizuku/zh-hans/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 了解更多\nactionLink: /zh-hans/introduction.html\nfeatures:\n- title: 优雅地使用系统 API\n  details: 忘掉 root shell 吧，你可以「直接使用」需要高权限的 API。此外，Shizuku 比 shell 要快得多。\n- title: 支持 adb 使用\n  details: 如果你的「需要 root 的应用」只需要 adb 权限，则可以使用 Shizuku 轻松地扩大用户群体。\n- title: 节省时间\n  details: Shizuku 有详细的文档引导用户，你只需要让用户安装 Shizuku。\nfooter: Copyright © 2019 RikkaApps\n---\n\n### 就像是系统应用一样简单\n\n```java\nprivate static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(\n    new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(\"package\")));\n\npublic static void grantRuntimePermission(String packageName, String permissionName, int userId) {\n    try {\n        PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);\n    } catch (RemoteException tr) {\n        throw new RuntimeException(tr.getMessage(), tr);\n    }\n}\n```\n\n::: tip\n\n还有一些步骤要做，比如检查权限或 Shizuku 是否正在运行。\n:::"
  },
  {
    "path": "shizuku/zh-hans/download.md",
    "content": "# 下载\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)\n\n[Coolapk](https://www.coolapk.com/apk/moe.shizuku.privileged.api)\n\n[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)"
  },
  {
    "path": "shizuku/zh-hans/guide/setup.md",
    "content": "# 用户手册\n\n[[toc]]\n\n## 启动 Shizuku\n\nShizuku 支持通过以下三种方式启动。\n\n::: tip 如果您正在使用 GrapheneOS\n\n您可能需要关闭 系统设置 - “安全” - “Secure app spawning”。\n\n[来源](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)\n\n:::\n\n### 通过 root 启动\n\n如果您的设备已经 root，直接启动即可。\n\n### 通过无线调试启动\n\n通过无线调试启动适用于 Android 11 或以上版本。这种启动方式无需连接电脑。由于系统限制，每次重新启动后都需要再次进行启动步骤。\n\n#### 启用无线调试\n\n1. 在网络上搜索如何为您的机型启用“开发者选项”\n2. 启用“开发者选项”和“USB 调试”<br><br><img :src=\"$withBase('/images/enable_dev_options.png')\" style=\"max-width:320px;width:100%\">\n3. 进入“无线调试”<br><br><img :src=\"$withBase('/images/enter_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n4. 启用“无线调试”<br><br><img :src=\"$withBase('/images/enable_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n   \n#### 配对（仅需一次）\n\n1. 在 Shizuku 内开始配对<br><img :src=\"$withBase('/images/start_paring_from_shizuku.png')\" style=\"max-width:320px;width:100%\">\n2. [启用无线调试](#启用无线调试)\n3. 点按“无线调试”中的“使用配对码配对设备”<br><img :src=\"$withBase('/images/start_pairing.png')\" style=\"max-width:320px;width:100%\">\n4. 在 Shizuku 的通知中填入配对码<br><img :src=\"$withBase('/images/enter_pairing_code.png')\" style=\"max-width:320px;width:100%\">\n\n#### 启动 Shizuku\n\n<img :src=\"$withBase('/images/start_shizuku.png')\" style=\"max-width:320px;width:100%\">\n\n如果无法启动，尝试禁用并启用无线调试。\n\n### 通过连接电脑启动\n\n该启动方式适用于未 root 且运行 Android 10 及以下版本的设备。很不幸，该启动方式需要连接电脑。由于系统限制，每次重新启动后都需要再次进行启动步骤。\n\n#### 什么是 `adb`？\n\nAndroid 调试桥 (`adb`) 是一个通用命令行工具，其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利，如安装和调试应用，并提供对 Unix shell（可用来在模拟器或连接的设备上运行各种命令）的访问。\n\n更多信息请查看 [Android Developer](https://developer.android.google.cn/studio/command-line/adb)。\n\n#### 安装 `adb`\n\n1. 下载由 Google 提供的“SDK 平台工具”并解压至任意文件夹\n\n   * [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)\n   * [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)\n   * [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)\n\n2. 打开文件夹，右键选择\n\n   * Windows 10：在此处打开 PowerShell 窗口（**需要按住 Shift 才会显示该选项**）\n   * Windows 7：在此处打开命令行窗口（**需要按住 Shift 才会显示该选项**）\n   * Mac 或 Linux：打开 Terminal（终端）\n\n3. 输入 `adb` 如果可以看到一长串内容而不是提示找不到 adb 则表示成功\n\n::: tip 提示\n1. 请不要关闭该窗口，后面提到的“终端”都是指此窗口（如果关闭请重新进行第 2 步）。\n2. 如果使用 PowerShell 或是 Linux 及 Mac，所有 `adb` 都要替换成 `./adb`。\n:::\n\n#### 设置 `adb`\n\n要使用 `adb` 你首先需要在设备上打开 USB 调试功能，通常需要经过以下步骤：\n\n1. 打开系统设置，进入关于\n2. 连续数次点击 \"Build number\" 后看到类似 \"You are a developer\" 的提示\n3. 此时你应该可以在设置中找到“开发者选项”，进入后开启“USB 调试”\n4. 连接设备到电脑，在终端中输入 `adb devices`\n5. 此时设备上会出现“是否允许调试”的对话框，勾选“总是允许”后确认\n6. 再次在终端中输入 `adb devices`，如无问题将会看到类似如下内容\n   ```\n   List of devices attached\n   XXX      device\n   ```\n\n::: tip\n不同设备开启“开发者选项”的步骤可能有所不同，请自己搜索。\n:::\n\n#### 启动 Shizuku\n\n复制指令并粘贴到终端中，如无问题你将会在 Shizuku 中看到已启动成功。\n\n::: details 适用于 Shizuku v11.2.0+ 的指令 \n\n```\nadb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh\n```\n:::\n\n## 常见问题\n\n许多厂商对 Android 系统进行了修改，这会造成 Shizuku 无法正常工作。\n\n### 通过无线调试启动：一直显示“正在搜索配对服务”\n\n请允许 Shizuku 在后台运行。\n\n搜索配对服务需要访问本地网络，许多厂商在应用不可见后立刻禁止应用访问网络。您可以在网络上搜索如何在您的设备上允许应用在后台运行。\n\n### 通过无线调试启动：点击“输入配对码”后立刻提示失败\n\n#### MIUI（小米、POCO）\n\n在系统设置的“通知管理”-“通知显示设置”将通知样式切换为“原生样式”。\n\n### 通过无线调试启动/通过连接电脑启动：adb 权限受限\n\n#### MIUI（小米、POCO）\n\n在“开发者选项”中开启“USB 调试（安全设置）”。**注意，这和“USB 调试”是两个分开的选项。**\n\n#### ColorOS（OPPO & OnePlus）\n\n在“开发者选项”中关闭“权限监控”。\n\n#### Flyme（魅族）\n\n在“开发者选项”中关闭“Flyme 支付保护”。\n\n### 通过无线调试启动/通过连接电脑启动：Shizuku 随机停止\n\n#### 所有设备\n\n- 保证 Shizuku 可以在后台运行。\n- 不要关闭“USB 调试”及“开发者选项”。\n- 在“开发者选项”中将 USB 使用模式改为“仅充电”。\n  \n  在 Android 8 上的选项是“选择 USB 配置”-“仅充电”。\n  \n  在 Android 9 及以上版本上选项是“默认 USB 配置”-“不进行数据传输”。\n\n- （Android 11+）启用“停用 adb 授权超时功能”选项\n\n#### EMUI (华为) \n\n在“开发者选项”中开启「“仅充电”模式下允许 ADB 调试选项」。\n\n#### MIUI（小米、POCO）\n\n不要使用“手机管家”的扫描功能，因为它会禁用开发者选项。\n\n#### Sony\n\n不要点击连接 USB 后弹出的对话框，因为这会导致 USB 使用模式发生变化。\n\n### 通过 root 启动：无法开机启动\n\n请允许 Shizuku 在后台运行。"
  },
  {
    "path": "shizuku/zh-hans/introduction.md",
    "content": "# 简介\n\nShizuku 可以帮助普通应用借助一个由 app_process 启动的 Java 进程直接以 adb 或 root 特权使用系统 API。\n\n> Shizuku 这个名字来自[这里](https://www.pixiv.net/artworks/75508584)。\n\n## Shizuku 为何而生？\n\nShizuku 的诞生主要有两大目的：\n\n1. 提供一个方便地使用系统 API 的方式\n2. 为部分只需要 adb 权限的应用开发提供便利\n\n## Shizuku 与“传统”做法对比\n\n### “传统”做法\n\n以启用/禁用组件为例，一些需要 root 权限的应用直接在 `su` 中执行 `pm disable`。\n\n1. 执行 `su`\n2. 执行 `pm disable`\n3. (pre-Pie) 使用 app_process 启动 Java 进程（[参见此处](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm)）\n4. (Pie+) 执行原生程序 `cmd`（[参见此处](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/)）\n5. 处理参数，通过 binder 与 system server 交互，处理结果输出文字结果\n\n其中每个“执行”都意味着新进程建立，su 内部使用 socket 与 su daemon 交互，大量的时间和性能被消耗在这样的过程中。（部分设计不佳的应用甚至会每次执行指令都执行一次 `su`）\n\n此类做法的缺点在于：\n\n1. **极慢**\n2. 需要处理文本来获取结果\n3. 功能受制于可用的指令\n4. 即使 adb 有足够权限，应用也需要 root 权限才可使用\n\n### Shizuku 做法\n\nShizuku app 会引导用户使用 root 或是 adb 方式运行一个进程（Shizuku 服务进程）。\n\n1. 应用进程启动时 Shizuku 服务进程发送 binder 至应用进程\n2. 应用通过该 binder 与 Shizuku 服务进程交互，Shizuku 服务进程通过 binder 与 system server 交互\n\nShizuku 的优点在于：\n\n1. 极小额外时间及性能消耗\n2. 与直接调用 API 体验几乎一致（应用开发者只需添加少量代码）"
  },
  {
    "path": "shizuku/zh-hant/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 瞭解更多\nactionLink: /zh-hant/introduction.html\nfeatures:\n- title: 優雅地使用系統 API\n  details: 忘掉 root shell 吧，你可以「直接使用」需要高權限的 API。此外，Shizuku 比 shell 要快得多。\n- title: 支援 adb 使用\n  details: 如果你的「需要 root 的程式」只需要 adb 權限，則可以使用 Shizuku 輕鬆地擴大用戶羣體。\n- title: 節省時間\n  details: Shizuku 有詳細的文檔引導使用者，你只需要讓使用者安裝 Shizuku。\nfooter: Copyright © 2019 RikkaApps\n---\n\n### 就像是系統程序一樣簡單\n\n```java\nprivate static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(\n    new ShizukuBinderWrapper(SystemServiceHelper.getSystemService(\"package\")));\n\npublic static void grantRuntimePermission(String packageName, String permissionName, int userId) {\n    try {\n        PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);\n    } catch (RemoteException tr) {\n        throw new RuntimeException(tr.getMessage(), tr);\n    }\n}\n```\n\n::: tip\n\n還有一些步驟要做，比如檢查權限或 Shizuku 是否正在執行。\n:::"
  },
  {
    "path": "shizuku/zh-hant/download.md",
    "content": "# 下載\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)\n\n[Coolapk](https://www.coolapk.com/apk/moe.shizuku.privileged.api)\n\n[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)"
  },
  {
    "path": "shizuku/zh-hant/guide/setup.md",
    "content": "# 使用者手冊\n\n[[toc]]\n\n## 啟動 Shizuku\n\nShizuku 支援透過以下三種方式啟動。\n\n::: tip 如果您正在使用 GrapheneOS\n\n您可能需要關閉 系統設定 - 「安全」 - 「Secure app spawning」。\n\n[來源](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)\n\n:::\n\n### 透過 root 啟動\n\n對於已 root 裝置，直接啟動即可。\n\n### 透過無線偵錯啟動\n\n透過無線除錯啟動適用於 Android 11 或以上版本。這種啟動方式無需連線電腦。由於系統限制，每次重新啟動後都需要再次進行啟動步驟。\n\n#### 啟用無線偵錯\n\n1. 在網路上搜索如何為您的機型啟用「開發人員選項」\n2. 啟用「開發人員選項」和「USB 偵錯」<br><br><img :src=\"$withBase('/images/enable_dev_options.png')\" style=\"max-width:320px;width:100%\">\n3. 進入「無線偵錯」<br><br><img :src=\"$withBase('/images/enter_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n4. 啟用「無線偵錯」<br><br><img :src=\"$withBase('/images/enable_wireless_debugging.png')\" style=\"max-width:320px;width:100%\">\n   \n#### 配對（僅需一次）\n\n1. 在 Shizuku 內開始配對<br><img :src=\"$withBase('/images/start_paring_from_shizuku.png')\" style=\"max-width:320px;width:100%\">\n2. [啟用無線偵錯](#啟用無線偵錯)\n3. 點按「無線偵錯」中的「使用配對碼配對裝置」<br><img :src=\"$withBase('/images/start_pairing.png')\" style=\"max-width:320px;width:100%\">\n4. 在 Shizuku 的通知中填入配對碼<br><img :src=\"$withBase('/images/enter_pairing_code.png')\" style=\"max-width:320px;width:100%\">\n\n#### 啟動 Shizuku\n\n<img :src=\"$withBase('/images/start_shizuku.png')\" style=\"max-width:320px;width:100%\">\n\n如果無法啟動，嘗試禁用並啟用無線偵錯。\n\n### 透過連線電腦啟動\n\n該啟動方式適用於未 root 且執行 Android 10 及以下版本的裝置。很不幸，該啟動方式需要連線電腦。由於系統限制，每次重新啟動後都需要再次進行啟動步驟。\n\n#### 什麼是 `adb`？\n\nAndroid 除錯橋 (`adb`) 是一個通用命令列工具，其允許您與模擬器例項或連線的 Android 裝置進行通訊。它可為各種裝置操作提供便利，如安裝和除錯程式，並提供對 Unix shell（可用來在模擬器或連線的裝置上執行各種命令）的存取。\n\n更多資訊請檢視 [Android Developer](https://developer.android.com/studio/command-line/adb)。\n\n#### 安裝 `adb`\n\n1. 下載由 Google 提供的「SDK Platform Tools」並解壓至任意資料夾\n\n   * [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)\n   * [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)\n   * [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)\n\n2. 開啟資料夾，右鍵選擇\n\n   * Windows 10：在此處開啟 PowerShell 視窗（**需要按住 Shift 才會顯示該選項**）\n   * Windows 7：在此處開啟命令視窗（**需要按住 Shift 才會顯示該選項**）\n   * Mac 或 Linux：打开 Terminal（終端）\n\n3. 輸入 `adb` 如果可以看到一長串內容而不是提示找不到 adb 則表示成功\n\n::: tip 提示\n1. 請不要關閉該視窗，後面提到的「終端」都是指此視窗（如果關閉請重新進行第 2 步）。\n2. 如果使用 PowerShell 或是 Linux 及 Mac，所有 `adb` 都要替換成 `./adb`。\n:::\n\n#### 設定 `adb`\n\n要使用 `adb` 你首先需要在裝置上開啟 USB 偵錯功能，通常需要經過以下步驟：\n\n1. 開啟系統設定，進入關於\n2. 連續數次點選 \"Build number\" 後看到類似 \"You are a developer\" 的提示\n3. 此時你應該可以在設定中找到「開發人員選項」，進入後開啟「USB 偵錯」\n4. 連線裝置到電腦，在終端中輸入 `adb devices`\n5. 此時裝置上會出現「是否允許偵錯」的對話方塊，勾選「總是允許」後確認\n6. 再次在終端中輸入 `adb devices`，如無問題將會看到類似如下內容\n   ```\n   List of devices attached\n   XXX      device\n   ```\n\n::: tip\n不同裝置開啟「開發人員選項」的步驟可能有所不同，請自己搜尋。\n:::\n\n#### 啟動 Shizuku\n\n複製指令並貼上到終端中，如無問題你將會在 Shizuku 中看到已啟動成功。\n\n::: details 適用於 Shizuku v11.2.0+ 的指令 \n\n```\nadb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh\n```\n:::\n\n## 常見問題\n\n許多廠商對 Android 系統進行了修改，這會造成 Shizuku 無法正常工作。\n\n### 透過無線除錯啟動：一直顯示「正在搜尋配對服務」\n\n請允許 Shizuku 在背景執行。\n\n搜尋配對服務需要訪問本地網路，許多廠商在應用程式不可見後立刻禁止應用程式訪問網路。您可以在網路上搜索如何在您的裝置上允許應用程式在背景執行。\n\n### 透過無線除錯啟動：點選「輸入配對碼」後立刻提示失敗\n\n#### MIUI（Xiaomi、POCO）\n\n在系統設定的「通知管理」-「通知顯示設定」將通知樣式切換為「Android」。\n\n### 透過無線除錯啟動/透過連線電腦啟動：adb 權限受限\n\n#### MIUI（Xiaomi、POCO）\n\n在「開發人員選項」中開啟「USB 偵錯（安全設定）」。**注意，這和「USB 偵錯」是兩個分開的選項。**\n\n#### ColorOS（OPPO & OnePlus）\n\n你需要在「開發人員選項」中關閉「權限監控」。\n\n#### Flyme（魅族）\n\n你需要在「開發人員選項」中關閉「Flyme 支付保護」。\n\n### 透過無線除錯啟動/透過連線電腦啟動：Shizuku 隨機停止\n\n#### 所有裝置\n\n- 保證 Shizuku 可以在背景執行。\n- 不要關閉「USB 偵錯」及「開發人員選項」。\n- 在「開發人員選項」中將 USB 使用模式改為「僅充電」。\n  \n  在 Android 8 上的選項是「選擇 USB 配置」-「僅充電」。\n  \n  在 Android 9 及以上版本上選項是「預設 USB 配置」-「不進行資料傳輸」。\n\n- （Android 11+）啟用「停用 ADB 授權逾時」選項。\n\n#### EMUI (Huawei) \n\n你需要在「開發人員選項」中開啟「僅充電模式下允許 ADB 偵錯選項」。\n\n#### MIUI（Xiaomi、POCO）\n\n不要使用 MIUI 的「手機管家」的掃描功能，因為它會禁用「開發人員選項」。\n\n#### Sony\n\n不要點選連線 USB 後彈出的對話方塊，因為這會導致 USB 使用模式發生變化。\n\n### 透過 root 啟動：無法開機啟動\n\n請允許 Shizuku 在背景執行。\n"
  },
  {
    "path": "shizuku/zh-hant/introduction.md",
    "content": "# 簡介\n\nShizuku 可以幫助普通程式藉助一個由 app_process 啟動的 Java 程序直接以 adb 或 root 特權使用系統 API。\n\nShizuku 這個名字來自[這裡](https://www.pixiv.net/artworks/75508584)。\n\n## Shizuku 為何而生？\n\nShizuku 的誕生主要有兩大目的：\n\n1. 提供一個方便地使用系統 API 的方式\n2. 為部分只需要 adb 許可權的程式開發提供便利\n\n## Shizuku 與「傳統」做法對比\n\n### 「傳統」做法\n\n以啟用/停用元件為例，一些需要 root 許可權的程式直接在 `su` 中執行 `pm disable`。\n\n1. 執行 `su`\n2. 執行 `pm disable`\n3. (pre-Pie) 使用 app_process 啟動 Java 程序（[參見此處](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm)）\n4. (Pie+) 執行原生程式 `cmd`（[參見此處](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/)）\n5. 處理引數，通過 binder 與 system server 互動，處理結果輸出文字結果\n\n其中每個「執行」都意味著新程序建立，su 內部使用 socket 與 su daemon 互動，這樣的過程中消耗大量的時間和效能。（部分設計不佳的程式甚至會每次執行指令都執行一次 `su`）\n\n此類做法的缺點在於：\n\n1. **極慢**\n2. 需要處理文字來獲取結果\n3. 功能受制於可用的指令\n4. 即使 adb 有足夠許可權，程式也需要 root 許可權才可使用\n\n### Shizuku 做法\n\nShizuku app 會引導使用者使用 root 或是 adb 方式執行一個程序（Shizuku 服務程序）。\n\n1. 應用程序啟動時 Shizuku 服務程序傳送 binder 至應用程序\n2. 應用通過該 binder 與 Shizuku 服務程序互動，Shizuku 服務程序通過 binder 與 system server 互動\n\nShizuku 的優點在於：\n\n1. 極小額外時間及效能消耗\n2. 與直接呼叫 API 體驗幾乎一致（程式開發者只需新增少量程式碼）\n"
  },
  {
    "path": "storage_redirect/.gitignore",
    "content": "/.vuepress/dist"
  },
  {
    "path": "storage_redirect/.vuepress/config.js",
    "content": "const moment = require('moment')\nconst langMap = {\n  \"zh-Hans\": \"zh-cn\",\n  \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}\n\nmodule.exports = {\n  base: '/',\n  title: 'Storage Isolation',\n  head: [\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://raw.rikka.app/css/SourceCodePro-BDC.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]\n  ],\n  locales: {\n    '/': {\n      lang: 'en',\n      description: 'Elegantly solve the problem of bad apps abusing storage permissions'\n    },\n    '/zh-hans/': {\n      lang: 'zh-Hans',\n      title: '存储空间隔离',\n      description: '优雅地解决“坏应用”滥用存储权限的问题'\n    },\n    '/zh-hant/': {\n      lang: 'zh-Hant',\n      title: '儲存空間隔離',\n      description: '優雅地解決「壞應用程式」濫用儲存權限的問題'\n    }\n  },\n  themeConfig: {\n    locales: {\n      '/': {\n        selectText: 'Languages',\n        label: 'English',\n        serviceWorker: {\n          updatePopup: {\n            message: \"New content is available.\",\n            buttonText: \"Refresh\"\n          }\n        },\n        sidebar: getSidebar('/guide/', 'Guide', 'Advanced', 'Enhanced mode', 'Issues caused by OEMs', 'FAQ'),\n        nav: getNavbar('/', 'Guide', 'Download', 'Changelog', 'Rikka Apps'),\n        lastUpdated: 'Last Updated'\n      },\n      '/zh-hans/': {\n        selectText: '语言',\n        label: '简体中文',\n        editLinkText: '在 GitHub 上编辑此页',\n        serviceWorker: {\n          updatePopup: {\n            message: \"发现新内容可用.\",\n            buttonText: \"刷新\"\n          }\n        },\n        sidebar: getSidebar('/zh-hans/guide/', '指南', '高级', '增强模式', '厂商造成的问题', 'FAQ'),\n        nav: getNavbar('/zh-hans/', '指南', '下载', 'Changelog', 'Rikka Apps'),\n        lastUpdated: '最后更新'\n      },\n      '/zh-hant/': {\n        selectText: '語言',\n        label: '繁體中文',\n        editLinkText: '在 GitHub 上編輯此頁',\n        serviceWorker: {\n          updatePopup: {\n            message: \"發現新內容可用.\",\n            buttonText: \"重新整理\"\n          }\n        },\n        sidebar: getSidebar('/zh-hant/guide/', '指南', '高級', '增強模式', '廠商造成的問題', 'FAQ'),\n        nav: getNavbar('/zh-hant/', '指南', '下載', 'Changelog', 'Rikka Apps'),\n        lastUpdated: '最後更新'\n      }\n    },\n    displayAllHeaders: true,\n    sidebarDepth: 2,\n    serviceWorker: {\n      updatePopup: true\n    },\n    docsRepo: 'https://github.com/RikkaApps/websites',\n    docsDir: 'storage_redirect',\n    editLinks: true\n  },\n  plugins: [\n    [\n      'sitemap',\n      {\n        hostname: 'https://sr.rikka.app',\n        exclude: ['/404.html'],\n        dateFormatter: (time) => {\n          timestampCache[time]\n        }\n      }\n    ],\n    [\n      'clean-urls',\n      {\n        normalSuffix: '/',\n        indexSuffix: '/',\n        notFoundPath: '/404.html'\n      }\n    ],\n    [\n      '@vuepress/last-updated',\n      {\n        transformer: (timestamp, lang) => {\n          var original = timestamp\n\n          moment.locale(langMap[lang])\n          var localized = moment(original).format('lll')\n\n          moment.locale('en')\n          var iso = moment(original).toISOString()\n          timestampCache[localized] = iso\n\n          return localized\n        }\n      }\n    ]\n  ]\n}\n\nfunction getSidebar(prefix, basicTitle, advancedTitle, enhancedModeTitle, compatibilityTitle, faqTitle) {\n  var res = {}\n  res[prefix] = [\n    {\n      title: basicTitle,\n      collapsable: true,\n      sidebarDepth: 0,\n      children: [\n        '',\n        'tutorial',\n        'contribute',\n      ]\n    },\n    {\n      title: advancedTitle,\n      collapsable: true,\n      sidebarDepth: 0,\n      children: [\n        'advanced/shared_user_id',\n        'advanced/technical_details_export_isolated_files',\n      ]\n    },\n    {\n      title: enhancedModeTitle,\n      collapsable: true,\n      sidebarDepth: 0,\n      children: [\n        `enhanced_mode/`,\n        `enhanced_mode/install`,\n      ]\n    },\n    {\n      title: compatibilityTitle,\n      collapsable: true,\n      sidebarDepth: 0,\n      children: [\n        `compatibility/`,\n        `compatibility/samsung`,\n        `compatibility/meizu`,\n        `compatibility/miui`,\n      ]\n    },\n    {\n      title: faqTitle,\n      collapsable: true,\n      sidebarDepth: 0,\n      children: [\n        `faq/cant_find_app`,\n        `faq/how_to_report_problems`,\n        `faq/how_to_document`,\n      ]\n    }]\n  return res\n}\n\nfunction getNavbar(prefix, guide, download, changelog, allRikkaApps) {\n  return [\n    { text: guide, link: `${prefix}guide/` },\n    { text: download, link: `${prefix}download.html` },\n    { text: changelog, link: `${prefix}changelog.html` },\n    { text: allRikkaApps, link: `https://rikka.app${prefix}` },\n  ]\n}"
  },
  {
    "path": "storage_redirect/.vuepress/public/icon/browserconfig.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><square150x150logo src=\"/ms-icon-150x150.png\"/><square310x310logo src=\"/ms-icon-310x310.png\"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>"
  },
  {
    "path": "storage_redirect/.vuepress/public/icon/manifest.json",
    "content": "{\n \"name\": \"App\",\n \"icons\": [\n  {\n   \"src\": \"\\/android-icon-36x36.png\",\n   \"sizes\": \"36x36\",\n   \"type\": \"image\\/png\",\n   \"density\": \"0.75\"\n  },\n  {\n   \"src\": \"\\/android-icon-48x48.png\",\n   \"sizes\": \"48x48\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-72x72.png\",\n   \"sizes\": \"72x72\",\n   \"type\": \"image\\/png\",\n   \"density\": \"1.5\"\n  },\n  {\n   \"src\": \"\\/android-icon-96x96.png\",\n   \"sizes\": \"96x96\",\n   \"type\": \"image\\/png\",\n   \"density\": \"2.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-144x144.png\",\n   \"sizes\": \"144x144\",\n   \"type\": \"image\\/png\",\n   \"density\": \"3.0\"\n  },\n  {\n   \"src\": \"\\/android-icon-192x192.png\",\n   \"sizes\": \"192x192\",\n   \"type\": \"image\\/png\",\n   \"density\": \"4.0\"\n  }\n ]\n}"
  },
  {
    "path": "storage_redirect/.vuepress/theme/LICENSE",
    "content": "The MIT License (MIT)\n\nCopyright (c) 2018-present, Yuxi (Evan) You\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\nTHE SOFTWARE.\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/AlgoliaSearchBox.vue",
    "content": "<template>\n  <form\n    id=\"search-form\"\n    class=\"algolia-search-wrapper search-box\"\n    role=\"search\"\n  >\n    <input\n      id=\"algolia-search-input\"\n      class=\"search-query\"\n      :placeholder=\"placeholder\"\n    >\n  </form>\n</template>\n\n<script>\nexport default {\n  props: ['options'],\n\n  data () {\n    return {\n      placeholder: undefined\n    }\n  },\n\n  mounted () {\n    this.initialize(this.options, this.$lang)\n    this.placeholder = this.$site.themeConfig.searchPlaceholder || ''\n  },\n\n  methods: {\n    initialize (userOptions, lang) {\n      Promise.all([\n        import(/* webpackChunkName: \"docsearch\" */ 'docsearch.js/dist/cdn/docsearch.min.js'),\n        import(/* webpackChunkName: \"docsearch\" */ 'docsearch.js/dist/cdn/docsearch.min.css')\n      ]).then(([docsearch]) => {\n        docsearch = docsearch.default\n        const { algoliaOptions = {}} = userOptions\n        docsearch(Object.assign(\n          {},\n          userOptions,\n          {\n            inputSelector: '#algolia-search-input',\n            // #697 Make docsearch work well at i18n mode.\n            algoliaOptions: Object.assign({\n              'facetFilters': [`lang:${lang}`].concat(algoliaOptions.facetFilters || [])\n            }, algoliaOptions),\n            handleSelected: (input, event, suggestion) => {\n              const { pathname, hash } = new URL(suggestion.url)\n              this.$router.push(`${pathname}${hash}`)\n            }\n          }\n        ))\n      })\n    },\n\n    update (options, lang) {\n      this.$el.innerHTML = '<input id=\"algolia-search-input\" class=\"search-query\">'\n      this.initialize(options, lang)\n    }\n  },\n\n  watch: {\n    $lang (newValue) {\n      this.update(this.options, newValue)\n    },\n\n    options (newValue) {\n      this.update(newValue, this.$lang)\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.algolia-search-wrapper\n  & > span\n    vertical-align middle\n  .algolia-autocomplete\n    line-height normal\n    .ds-dropdown-menu\n      background-color #fff\n      border 1px solid #999\n      border-radius 4px\n      font-size 16px\n      margin 6px 0 0\n      padding 4px\n      text-align left\n      &:before\n        border-color #999\n      [class*=ds-dataset-]\n        border none\n        padding 0\n      .ds-suggestions\n        margin-top 0\n      .ds-suggestion\n        border-bottom 1px solid $borderColor\n    .algolia-docsearch-suggestion--highlight\n      color #2c815b\n    .algolia-docsearch-suggestion\n      border-color $borderColor\n      padding 0\n      .algolia-docsearch-suggestion--category-header\n        padding 5px 10px\n        margin-top 0\n        background $accentColor\n        color #fff\n        font-weight 600\n        .algolia-docsearch-suggestion--highlight\n          background rgba(255, 255, 255, 0.6)\n      .algolia-docsearch-suggestion--wrapper\n        padding 0\n      .algolia-docsearch-suggestion--title\n        font-weight 600\n        margin-bottom 0\n        color $textColor\n      .algolia-docsearch-suggestion--subcategory-column\n        vertical-align top\n        padding 5px 7px 5px 5px\n        border-color $borderColor\n        background #f1f3f5\n        &:after\n          display none\n      .algolia-docsearch-suggestion--subcategory-column-text\n        color #555\n    .algolia-docsearch-footer\n      border-color $borderColor\n    .ds-cursor .algolia-docsearch-suggestion--content\n      background-color #e7edf3 !important\n      color $textColor\n\n@media (min-width: $MQMobile)\n  .algolia-search-wrapper\n    .algolia-autocomplete\n      .algolia-docsearch-suggestion\n        .algolia-docsearch-suggestion--subcategory-column\n          float none\n          width 150px\n          min-width 150px\n          display table-cell\n        .algolia-docsearch-suggestion--content\n          float none\n          display table-cell\n          width 100%\n          vertical-align top\n        .ds-dropdown-menu\n          min-width 515px !important\n\n@media (max-width: $MQMobile)\n  .algolia-search-wrapper\n    .ds-dropdown-menu\n      min-width calc(100vw - 4rem) !important\n      max-width calc(100vw - 4rem) !important\n    .algolia-docsearch-suggestion--wrapper\n      padding 5px 7px 5px 5px !important\n    .algolia-docsearch-suggestion--subcategory-column\n      padding 0 !important\n      background white !important\n    .algolia-docsearch-suggestion--subcategory-column-text:after\n      content \" > \"\n      font-size 10px\n      line-height 14.4px\n      display inline-block\n      width 5px\n      margin -3px 3px 0\n      vertical-align middle\n\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/Download.vue",
    "content": "<template>\n  <main class=\"download\">\n  </main>\n</template>\n\n<script>\nexport default {\n  computed: {\n    data() {\n      return this.$page.frontmatter;\n    }\n  }\n};\n</script>"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/DropdownLink.vue",
    "content": "<template>\n  <div\n    class=\"dropdown-wrapper\"\n    :class=\"{ open }\"\n  >\n    <a\n      class=\"dropdown-title\"\n      @click=\"toggle\"\n    >\n      <span class=\"title\">{{ item.text }}</span>\n      <span\n        class=\"arrow\"\n        :class=\"open ? 'down' : 'right'\"\n      ></span>\n    </a>\n\n    <DropdownTransition>\n      <ul\n        class=\"nav-dropdown\"\n        v-show=\"open\"\n      >\n        <li\n          class=\"dropdown-item\"\n          :key=\"subItem.link || index\"\n          v-for=\"(subItem, index) in item.items\"\n        >\n          <h4 v-if=\"subItem.type === 'links'\">{{ subItem.text }}</h4>\n\n          <ul\n            class=\"dropdown-subitem-wrapper\"\n            v-if=\"subItem.type === 'links'\"\n          >\n            <li\n              class=\"dropdown-subitem\"\n              :key=\"childSubItem.link\"\n              v-for=\"childSubItem in subItem.items\"\n            >\n              <NavLink :item=\"childSubItem\"/>\n            </li>\n          </ul>\n\n          <NavLink\n            v-else\n            :item=\"subItem\"\n          />\n        </li>\n      </ul>\n    </DropdownTransition>\n  </div>\n</template>\n\n<script>\nimport NavLink from '@theme/components/NavLink.vue'\nimport DropdownTransition from '@theme/components/DropdownTransition.vue'\n\nexport default {\n  components: { NavLink, DropdownTransition },\n\n  data () {\n    return {\n      open: false\n    }\n  },\n\n  props: {\n    item: {\n      required: true\n    }\n  },\n\n  methods: {\n    toggle () {\n      this.open = !this.open\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.dropdown-wrapper\n  cursor pointer\n  .dropdown-title\n    display block\n    &:hover\n      border-color transparent\n    .arrow\n      vertical-align middle\n      margin-top -1px\n      margin-left 0.4rem\n  .nav-dropdown\n    .dropdown-item\n      color inherit\n      line-height 1.7rem\n      h4\n        margin 0.45rem 0 0\n        border-top 1px solid #eee\n        padding 0.45rem 1.5rem 0 1.25rem\n      .dropdown-subitem-wrapper\n        padding 0\n        list-style none\n        .dropdown-subitem\n          font-size 0.9em\n      a\n        display block\n        line-height 1.7rem\n        position relative\n        border-bottom none\n        font-weight 400\n        margin-bottom 0\n        padding 0 1.5rem 0 1.25rem\n        &:hover\n          color $accentColor\n        &.router-link-active\n          color $accentColor\n          &::after\n            content \"\"\n            width 0\n            height 0\n            border-left 5px solid $accentColor\n            border-top 3px solid transparent\n            border-bottom 3px solid transparent\n            position absolute\n            top calc(50% - 2px)\n            left 9px\n      &:first-child h4\n        margin-top 0\n        padding-top 0\n        border-top 0\n\n@media (max-width: $MQMobile)\n  .dropdown-wrapper\n    &.open .dropdown-title\n      margin-bottom 0.5rem\n    .nav-dropdown\n      transition height .1s ease-out\n      overflow hidden\n      .dropdown-item\n        h4\n          border-top 0\n          margin-top 0\n          padding-top 0\n        h4, & > a\n          font-size 15px\n          line-height 2rem\n        .dropdown-subitem\n          font-size 14px\n          padding-left 1rem\n\n@media (min-width: $MQMobile)\n  .dropdown-wrapper\n    height 1.8rem\n    &:hover .nav-dropdown\n      // override the inline style.\n      display block !important\n    .dropdown-title .arrow\n      // make the arrow always down at desktop\n      border-left 4px solid transparent\n      border-right 4px solid transparent\n      border-top 6px solid $arrowBgColor\n      border-bottom 0\n    .nav-dropdown\n      display none\n      // Avoid height shaked by clicking\n      height auto !important\n      box-sizing border-box;\n      max-height calc(100vh - 2.7rem)\n      overflow-y auto\n      position absolute\n      top 100%\n      right 0\n      background-color #fff\n      padding 0.6rem 0\n      border 1px solid #ddd\n      border-bottom-color #ccc\n      text-align left\n      border-radius 0.25rem\n      white-space nowrap\n      margin 0\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/DropdownTransition.vue",
    "content": "<template>\n  <transition\n    name=\"dropdown\"\n    @enter=\"setHeight\"\n    @after-enter=\"unsetHeight\"\n    @before-leave=\"setHeight\"\n  >\n    <slot/>\n  </transition>\n</template>\n\n<script>\nexport default {\n  name: 'DropdownTransition',\n\n  methods: {\n    setHeight (items) {\n      // explicitly set height so that it can be transitioned\n      items.style.height = items.scrollHeight + 'px'\n    },\n\n    unsetHeight (items) {\n      items.style.height = ''\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.dropdown-enter, .dropdown-leave-to\n  height 0 !important\n\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/Home.vue",
    "content": "<template>\n  <main class=\"home\" aria-labelledby=\"main-title\">\n    <header class=\"hero\">\n      <img\n        v-if=\"data.heroImage\"\n        :src=\"$withBase(data.heroImage)\"\n        :alt=\"data.heroAlt || 'hero'\"\n      >\n\n      <h1 v-if=\"data.heroText !== null\" id=\"main-title\">{{ data.heroText || $title || 'Hello' }}</h1>\n\n      <p class=\"description\">\n        {{ data.tagline || $description || 'Welcome to your VuePress site' }}\n      </p>\n\n\t  <div class=\"actions\">\n\t    <div\n          class=\"action\"\n          v-if=\"data.secondaryActionText && data.secondaryActionLink\"\n        >\n          <NavLink\n            class=\"action-button secondary\"\n            :item=\"secondaryActionLink\"\n          />\n      </div>\n\t    \n\t    <div\n          class=\"action\"\n          v-if=\"data.actionText && data.actionLink\"\n        >\n          <NavLink\n            class=\"action-button\"\n            :item=\"actionLink\"\n          />\n      </div>\n\t  </div>\n    </header>\n\n    <div\n      class=\"features\"\n      v-if=\"data.features && data.features.length\"\n    >\n      <div\n        class=\"feature\"\n        v-for=\"(feature, index) in data.features\"\n        :key=\"index\"\n      >\n        <h2>{{ feature.title }}</h2>\n        <p>{{ feature.details }}</p>\n      </div>\n    </div>\n\n    <Content class=\"theme-default-content custom\"/>\n\n    <div\n      class=\"footer\"\n      v-if=\"data.footer\"\n    >\n      {{ data.footer }}\n    </div>\n  </main>\n</template>\n\n<script>\nimport NavLink from '@theme/components/NavLink.vue'\n\nexport default {\n  components: { NavLink },\n\n  computed: {\n    data () {\n      return this.$page.frontmatter\n    },\n\n    actionLink () {\n      return {\n        link: this.data.actionLink,\n        text: this.data.actionText\n      }\n    },\n\t\n\tsecondaryActionLink () {\n      return {\n        link: this.data.secondaryActionLink,\n        text: this.data.secondaryActionText\n      }\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.home\n  padding $navbarHeight 2rem 0\n  max-width 960px\n  margin 0px auto\n  display block\n  .hero\n    text-align center\n    img\n      max-width: 100%\n      max-height 280px\n      display block\n      margin 3rem auto 1.5rem\n    h1\n      font-size 3rem\n\t h1, .description, .actions\n      margin 1.8rem auto\n    .description\n      max-width 35rem\n      font-size 1.6rem\n      line-height 1.3\n      color lighten($textColor, 40%)\n\t.action\n\t  margin 0.6rem\n\t.actions\n      display flex\n      flex-wrap wrap\n      align-items flex-start\n      align-content stretch\n      justify-content center\n    .action-button\n      display inline-block\n      font-size 1.2rem\n      color #fff\n      background-color $accentColor\n      padding 0.8rem 1.6rem\n      border-radius 4px\n      transition background-color .1s ease\n      box-sizing border-box\n      border-bottom 1px solid darken($accentColor, 10%)\n      &:hover\n        background-color lighten($accentColor, 10%)\n\t  .secondary\n        color $textColor\n        background-color #fff\n        transition background-color .1s ease\n        border 1px solid darken($textColor, 10%)\n        &:hover\n          background-color lighten($textColor, 90%)\n  .features\n    border-top 1px solid $borderColor\n    padding 1.2rem 0\n    margin-top 2.5rem\n    display flex\n    flex-wrap wrap\n    align-items flex-start\n    align-content stretch\n    justify-content space-between\n  .feature\n    flex-grow 1\n    flex-basis 30%\n    max-width 30%\n    h2\n      font-size 1.4rem\n      font-weight 500\n      border-bottom none\n      padding-bottom 0\n      color lighten($textColor, 10%)\n    p\n      color lighten($textColor, 25%)\n  .footer\n    padding 2.5rem\n    border-top 1px solid $borderColor\n    text-align center\n    color lighten($textColor, 25%)\n\n@media (max-width: $MQMobile)\n  .home\n    .features\n      flex-direction column\n    .feature\n      max-width 100%\n      padding 0 2.5rem\n\n@media (max-width: $MQMobileNarrow)\n  .home\n    padding-left 1.5rem\n    padding-right 1.5rem\n    .hero\n      img\n        max-height 210px\n        margin 2rem auto 1.2rem\n      h1\n        font-size 2rem\n      h1, .description, .actions\n        margin 1.2rem auto\n      .description\n        font-size 1.2rem\n      .action-button\n        font-size 1rem\n        padding 0.6rem 1.2rem\n    .feature\n      h2\n        font-size 1.25rem\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/NavLink.vue",
    "content": "<template>\n  <router-link\n    class=\"nav-link\"\n    :to=\"link\"\n    v-if=\"!isExternal(link)\"\n    :exact=\"exact\"\n  >{{ item.text }}</router-link>\n  <a\n    v-else\n    :href=\"link\"\n    class=\"nav-link external\"\n    :target=\"isMailto(link) || isTel(link) ? null : '_blank'\"\n    :rel=\"isMailto(link) || isTel(link) ? null : 'noopener noreferrer'\"\n  >\n    {{ item.text }}\n    <OutboundLink/>\n  </a>\n</template>\n\n<script>\nimport { isExternal, isMailto, isTel, ensureExt } from '../util'\n\nexport default {\n  props: {\n    item: {\n      required: true\n    }\n  },\n\n  computed: {\n    link () {\n      return ensureExt(this.item.link)\n    },\n\n    exact () {\n      if (this.$site.locales) {\n        return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)\n      }\n      return this.link === '/'\n    }\n  },\n\n  methods: {\n    isExternal,\n    isMailto,\n    isTel\n  }\n}\n</script>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/NavLinks.vue",
    "content": "<template>\n  <nav\n    class=\"nav-links\"\n    v-if=\"userLinks.length || repoLink\"\n  >\n    <!-- user links -->\n    <div\n      class=\"nav-item\"\n      v-for=\"item in userLinks\"\n      :key=\"item.link\"\n    >\n      <DropdownLink\n        v-if=\"item.type === 'links'\"\n        :item=\"item\"\n      />\n      <NavLink\n        v-else\n        :item=\"item\"\n      />\n    </div>\n\n    <!-- repo link -->\n    <a\n      v-if=\"repoLink\"\n      :href=\"repoLink\"\n      class=\"repo-link\"\n      target=\"_blank\"\n      rel=\"noopener noreferrer\"\n    >\n      {{ repoLabel }}\n      <OutboundLink/>\n    </a>\n  </nav>\n</template>\n\n<script>\nimport DropdownLink from '@theme/components/DropdownLink.vue'\nimport { resolveNavLinkItem } from '../util'\nimport NavLink from '@theme/components/NavLink.vue'\n\nexport default {\n  components: { NavLink, DropdownLink },\n\n  computed: {\n    userNav () {\n      return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []\n    },\n\n    nav () {\n      const { locales } = this.$site\n      if (locales && Object.keys(locales).length > 1) {\n        const currentLink = this.$page.path\n        const routes = this.$router.options.routes\n        const themeLocales = this.$site.themeConfig.locales || {}\n        const languageDropdown = {\n          text: this.$themeLocaleConfig.selectText || 'Languages',\n          items: Object.keys(locales).map(path => {\n            const locale = locales[path]\n            const text = themeLocales[path] && themeLocales[path].label || locale.lang\n            let link\n            // Stay on the current page\n            if (locale.lang === this.$lang) {\n              link = currentLink\n            } else {\n              // Try to stay on the same page\n              link = currentLink.replace(this.$localeConfig.path, path)\n              // fallback to homepage\n              if (!routes.some(route => route.path === link)) {\n                link = path\n              }\n            }\n            return { text, link }\n          })\n        }\n        return [...this.userNav, languageDropdown]\n      }\n      return this.userNav\n    },\n\n    userLinks () {\n      return (this.nav || []).map(link => {\n        return Object.assign(resolveNavLinkItem(link), {\n          items: (link.items || []).map(resolveNavLinkItem)\n        })\n      })\n    },\n\n    repoLink () {\n      const { repo } = this.$site.themeConfig\n      if (repo) {\n        return /^https?:/.test(repo)\n          ? repo\n          : `https://github.com/${repo}`\n      }\n    },\n\n    repoLabel () {\n      if (!this.repoLink) return\n      if (this.$site.themeConfig.repoLabel) {\n        return this.$site.themeConfig.repoLabel\n      }\n\n      const repoHost = this.repoLink.match(/^https?:\\/\\/[^/]+/)[0]\n      const platforms = ['GitHub', 'GitLab', 'Bitbucket']\n      for (let i = 0; i < platforms.length; i++) {\n        const platform = platforms[i]\n        if (new RegExp(platform, 'i').test(repoHost)) {\n          return platform\n        }\n      }\n\n      return 'Source'\n    }\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.nav-links\n  display inline-block\n  a\n    line-height 1.4rem\n    color inherit\n    &:hover, &.router-link-active\n      color $accentColor\n  .nav-item\n    position relative\n    display inline-block\n    margin-left 1.5rem\n    line-height 2rem\n    &:first-child\n      margin-left 0\n  .repo-link\n    margin-left 1.5rem\n\n@media (max-width: $MQMobile)\n  .nav-links\n    .nav-item, .repo-link\n      margin-left 0\n\n@media (min-width: $MQMobile)\n  .nav-links a\n    &:hover, &.router-link-active\n      color $textColor\n  .nav-item > a:not(.external)\n    &:hover, &.router-link-active\n      margin-bottom -2px\n      border-bottom 2px solid lighten($accentColor, 8%)\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/Navbar.vue",
    "content": "<template>\n  <header class=\"navbar\">\n    <SidebarButton @toggle-sidebar=\"$emit('toggle-sidebar')\"/>\n\n    <router-link\n      :to=\"$localePath\"\n      class=\"home-link\"\n    >\n      <img\n        class=\"logo\"\n        v-if=\"$site.themeConfig.logo\"\n        :src=\"$withBase($site.themeConfig.logo)\"\n        :alt=\"$siteTitle\"\n      >\n      <span\n        ref=\"siteName\"\n        class=\"site-name\"\n        v-if=\"$siteTitle\"\n        :class=\"{ 'can-hide': $site.themeConfig.logo }\"\n      >{{ $siteTitle }}</span>\n    </router-link>\n\n    <div\n      class=\"links\"\n      :style=\"linksWrapMaxWidth ? {\n        'max-width': linksWrapMaxWidth + 'px'\n      } : {}\"\n    >\n      <AlgoliaSearchBox\n        v-if=\"isAlgoliaSearch\"\n        :options=\"algolia\"\n      />\n      <SearchBox v-else-if=\"$site.themeConfig.search !== false && $page.frontmatter.search !== false\"/>\n      <NavLinks class=\"can-hide\"/>\n    </div>\n  </header>\n</template>\n\n<script>\nimport AlgoliaSearchBox from '@AlgoliaSearchBox'\nimport SearchBox from '@SearchBox'\nimport SidebarButton from '@theme/components/SidebarButton.vue'\nimport NavLinks from '@theme/components/NavLinks.vue'\n\nexport default {\n  components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox },\n\n  data () {\n    return {\n      linksWrapMaxWidth: null\n    }\n  },\n\n  mounted () {\n    const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl\n    const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))\n    const handleLinksWrapWidth = () => {\n      if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {\n        this.linksWrapMaxWidth = null\n      } else {\n        this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING\n          - (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)\n      }\n    }\n    handleLinksWrapWidth()\n    window.addEventListener('resize', handleLinksWrapWidth, false)\n  },\n\n  computed: {\n    algolia () {\n      return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}\n    },\n\n    isAlgoliaSearch () {\n      return this.algolia && this.algolia.apiKey && this.algolia.indexName\n    }\n  }\n}\n\nfunction css (el, property) {\n  // NOTE: Known bug, will return 'auto' if style value is 'auto'\n  const win = el.ownerDocument.defaultView\n  // null means not to return pseudo styles\n  return win.getComputedStyle(el, null)[property]\n}\n</script>\n\n<style lang=\"stylus\">\n$navbar-vertical-padding = 0.7rem\n$navbar-horizontal-padding = 1.5rem\n\n.navbar\n  padding $navbar-vertical-padding $navbar-horizontal-padding\n  line-height $navbarHeight - 1.4rem\n  a, span, img\n    display inline-block\n  .logo\n    height $navbarHeight - 1.4rem\n    min-width $navbarHeight - 1.4rem\n    margin-right 0.8rem\n    vertical-align top\n  .site-name\n    font-size 1.3rem\n    font-weight 600\n    color $textColor\n    position relative\n  .links\n    padding-left 1.5rem\n    box-sizing border-box\n    background-color white\n    white-space nowrap\n    font-size 0.9rem\n    position absolute\n    right $navbar-horizontal-padding\n    top $navbar-vertical-padding\n    display flex\n    .search-box\n      flex: 0 0 auto\n      vertical-align top\n\n@media (max-width: $MQMobile)\n  .navbar\n    padding-left 4rem\n    .can-hide\n      display none\n    .links\n      padding-left 1.5rem\n    .site-name\n      width calc(100vw - 9.4rem)\n      overflow hidden\n      white-space nowrap\n      text-overflow ellipsis\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/Page.vue",
    "content": "<template>\n  <main class=\"page\">\n    <slot name=\"top\" />\n\n    <Content class=\"theme-default-content\" />\n    <PageEdit />\n\n    <PageNav v-bind=\"{ sidebarItems }\" />\n\n    <slot name=\"bottom\" />\n  </main>\n</template>\n\n<script>\nimport PageEdit from '@theme/components/PageEdit.vue'\nimport PageNav from '@theme/components/PageNav.vue'\n\nexport default {\n  components: { PageEdit, PageNav },\n  props: ['sidebarItems']\n}\n</script>\n\n<style lang=\"stylus\">\n@require '../styles/wrapper.styl';\n\n.page {\n  padding-bottom: 2rem;\n  display: block;\n}\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/PageEdit.vue",
    "content": "<template>\n  <footer class=\"page-edit\">\n    <div class=\"edit-link\" v-if=\"editLink\">\n      <a :href=\"editLink\" target=\"_blank\" rel=\"noopener noreferrer\">{{ editLinkText }}</a>\n      <OutboundLink />\n    </div>\n\n    <div class=\"last-updated\" v-if=\"lastUpdated\">\n      <span class=\"prefix\">{{ lastUpdatedText }}:</span>\n      <span class=\"time\">{{ lastUpdated }}</span>\n    </div>\n  </footer>\n</template>\n<script>\nimport { endingSlashRE, outboundRE } from '../util'\n\nexport default {\n  name: 'PageEdit',\n  computed: {\n    lastUpdated () {\n      return this.$page.lastUpdated\n    },\n\n    lastUpdatedText () {\n      if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {\n        return this.$themeLocaleConfig.lastUpdated\n      }\n      if (typeof this.$site.themeConfig.lastUpdated === 'string') {\n        return this.$site.themeConfig.lastUpdated\n      }\n      return 'Last Updated'\n    },\n\n    editLink () {\n      if (this.$page.frontmatter.editLink === false) {\n        return\n      }\n      const {\n        repo,\n        editLinks,\n        docsDir = '',\n        docsBranch = 'master',\n        docsRepo = repo\n      } = this.$site.themeConfig\n\n      if (docsRepo && editLinks && this.$page.relativePath) {\n        return this.createEditLink(\n          repo,\n          docsRepo,\n          docsDir,\n          docsBranch,\n          this.$page.relativePath\n        )\n      }\n    },\n\n    editLinkText () {\n      return (\n        this.$themeLocaleConfig.editLinkText\n        || this.$site.themeConfig.editLinkText\n        || `Edit this page`\n      )\n    }\n  },\n\n  methods: {\n    createEditLink (repo, docsRepo, docsDir, docsBranch, path) {\n      const bitbucket = /bitbucket.org/\n      if (bitbucket.test(repo)) {\n        const base = outboundRE.test(docsRepo) ? docsRepo : repo\n        return (\n          base.replace(endingSlashRE, '')\n          + `/src`\n          + `/${docsBranch}/`\n          + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')\n          + path\n          + `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`\n        )\n      }\n\n      const base = outboundRE.test(docsRepo)\n        ? docsRepo\n        : `https://github.com/${docsRepo}`\n      return (\n        base.replace(endingSlashRE, '')\n        + `/edit`\n        + `/${docsBranch}/`\n        + (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')\n        + path\n      )\n    }\n  }\n}\n</script>\n<style lang=\"stylus\">\n@require '../styles/wrapper.styl';\n\n.page-edit {\n  @extend $wrapper;\n  padding-top: 1rem;\n  padding-bottom: 1rem;\n  overflow: auto;\n\n  .edit-link {\n    display: inline-block;\n\n    a {\n      color: lighten($textColor, 25%);\n      margin-right: 0.25rem;\n    }\n  }\n\n  .last-updated {\n    float: right;\n    font-size: 0.9em;\n\n    .prefix {\n      font-weight: 500;\n      color: lighten($textColor, 25%);\n    }\n\n    .time {\n      font-weight: 400;\n      color: #aaa;\n    }\n  }\n}\n\n@media (max-width: $MQMobile) {\n  .page-edit {\n    .edit-link {\n      margin-bottom: 0.5rem;\n    }\n\n    .last-updated {\n      font-size: 0.8em;\n      float: none;\n      text-align: left;\n    }\n  }\n}\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/PageNav.vue",
    "content": "<template>\n  <div class=\"page-nav\" v-if=\"prev || next\">\n    <p class=\"inner\">\n      <span v-if=\"prev\" class=\"prev\">\n        ←\n        <router-link v-if=\"prev\" class=\"prev\" :to=\"prev.path\">{{ prev.title || prev.path }}</router-link>\n      </span>\n\n      <span v-if=\"next\" class=\"next\">\n        <router-link v-if=\"next\" :to=\"next.path\">{{ next.title || next.path }}</router-link>→\n      </span>\n    </p>\n  </div>\n</template>\n<script>\nimport { resolvePage } from '../util'\nimport isString from 'lodash/isString'\nimport isNil from 'lodash/isNil'\n\nexport default {\n  name: 'PageNav',\n  props: ['sidebarItems'],\n  computed: {\n    prev () {\n      return resolvePageLink(LINK_TYPES.PREV, this)\n    },\n\n    next () {\n      return resolvePageLink(LINK_TYPES.NEXT, this)\n    }\n  }\n}\n\nfunction resolvePrev (page, items) {\n  return find(page, items, -1)\n}\n\nfunction resolveNext (page, items) {\n  return find(page, items, 1)\n}\n\nconst LINK_TYPES = {\n  NEXT: {\n    resolveLink: resolveNext,\n    getThemeLinkConfig: ({ nextLinks }) => nextLinks,\n    getPageLinkConfig: ({ frontmatter }) => frontmatter.next\n  },\n  PREV: {\n    resolveLink: resolvePrev,\n    getThemeLinkConfig: ({ prevLinks }) => prevLinks,\n    getPageLinkConfig: ({ frontmatter }) => frontmatter.prev\n  }\n}\n\nfunction resolvePageLink (\n  linkType,\n  { $themeConfig, $page, $route, $site, sidebarItems }\n) {\n  const { resolveLink, getThemeLinkConfig, getPageLinkConfig } = linkType\n\n  // Get link config from theme\n  const themeLinkConfig = getThemeLinkConfig($themeConfig)\n\n  // Get link config from current page\n  const pageLinkConfig = getPageLinkConfig($page)\n\n  // Page link config will overwrite global theme link config if defined\n  const link = isNil(pageLinkConfig) ? themeLinkConfig : pageLinkConfig\n\n  if (link === false) {\n    return\n  } else if (isString(link)) {\n    return resolvePage($site.pages, link, $route.path)\n  } else {\n    return resolveLink($page, sidebarItems)\n  }\n}\n\nfunction find (page, items, offset) {\n  const res = []\n  flatten(items, res)\n  for (let i = 0; i < res.length; i++) {\n    const cur = res[i]\n    if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) {\n      return res[i + offset]\n    }\n  }\n}\n\nfunction flatten (items, res) {\n  for (let i = 0, l = items.length; i < l; i++) {\n    if (items[i].type === 'group') {\n      flatten(items[i].children || [], res)\n    } else {\n      res.push(items[i])\n    }\n  }\n}\n</script>\n<style lang=\"stylus\">\n@require '../styles/wrapper.styl';\n\n.page-nav {\n  @extend $wrapper;\n  padding-top: 1rem;\n  padding-bottom: 0;\n\n  .inner {\n    min-height: 2rem;\n    margin-top: 0;\n    border-top: 1px solid $borderColor;\n    padding-top: 1rem;\n    overflow: auto; // clear float\n  }\n\n  .next {\n    float: right;\n  }\n}\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/Sidebar.vue",
    "content": "<template>\n  <aside class=\"sidebar\">\n    <NavLinks/>\n    <slot name=\"top\"/>\n    <SidebarLinks :depth=\"0\" :items=\"items\"/>\n    <slot name=\"bottom\"/>\n  </aside>\n</template>\n\n<script>\nimport SidebarLinks from '@theme/components/SidebarLinks.vue'\nimport NavLinks from '@theme/components/NavLinks.vue'\n\nexport default {\n  name: 'Sidebar',\n\n  components: { SidebarLinks, NavLinks },\n\n  props: ['items']\n}\n</script>\n\n<style lang=\"stylus\">\n.sidebar\n  ul\n    padding 0\n    margin 0\n    list-style-type none\n  a\n    display inline-block\n  .nav-links\n    display none\n    border-bottom 1px solid $borderColor\n    padding 0.5rem 0 0.75rem 0\n    a\n      font-weight 600\n    .nav-item, .repo-link\n      display block\n      line-height 1.25rem\n      font-size 1.1em\n      padding 0.5rem 0 0.5rem 1.5rem\n  & > .sidebar-links\n    padding 1.5rem 0\n    & > li > a.sidebar-link\n      font-size 1.1em\n      line-height 1.7\n      font-weight bold\n    & > li:not(:first-child)\n      margin-top .75rem\n\n@media (max-width: $MQMobile)\n  .sidebar\n    .nav-links\n      display block\n      .dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after\n        top calc(1rem - 2px)\n    & > .sidebar-links\n      padding 1rem 0\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/SidebarButton.vue",
    "content": "<template>\n  <div class=\"sidebar-button\" @click=\"$emit('toggle-sidebar')\">\n    <svg class=\"icon\" xmlns=\"http://www.w3.org/2000/svg\" aria-hidden=\"true\" role=\"img\" viewBox=\"0 0 448 512\">\n      <path fill=\"currentColor\" d=\"M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z\" class=\"\"></path>\n    </svg>\n  </div>\n</template>\n\n<style lang=\"stylus\">\n.sidebar-button\n  cursor pointer\n  display none\n  width 1.25rem\n  height 1.25rem\n  position absolute\n  padding 0.6rem\n  top 0.6rem\n  left 1rem\n  .icon\n    display block\n    width 1.25rem\n    height 1.25rem\n\n@media (max-width: $MQMobile)\n  .sidebar-button\n    display block\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/SidebarGroup.vue",
    "content": "<template>\n  <section\n    class=\"sidebar-group\"\n    :class=\"[\n      {\n        collapsable,\n        'is-sub-group': depth !== 0\n      },\n      `depth-${depth}`\n    ]\"\n  >\n    <router-link\n      v-if=\"item.path\"\n      class=\"sidebar-heading clickable\"\n      :class=\"{\n        open,\n        'active': isActive($route, item.path)\n      }\"\n      :to=\"item.path\"\n      @click.native=\"$emit('toggle')\"\n    >\n      <span>{{ item.title }}</span>\n      <span\n        class=\"arrow\"\n        v-if=\"collapsable\"\n        :class=\"open ? 'down' : 'right'\">\n      </span>\n    </router-link>\n\n    <p\n      v-else\n      class=\"sidebar-heading\"\n      :class=\"{ open }\"\n      @click=\"$emit('toggle')\"\n    >\n      <span>{{ item.title }}</span>\n      <span\n        class=\"arrow\"\n        v-if=\"collapsable\"\n        :class=\"open ? 'down' : 'right'\">\n      </span>\n    </p>\n\n    <DropdownTransition>\n      <SidebarLinks\n        class=\"sidebar-group-items\"\n        :items=\"item.children\"\n        v-if=\"open || !collapsable\"\n        :sidebarDepth=\"item.sidebarDepth\"\n        :depth=\"depth + 1\"\n      />\n    </DropdownTransition>\n  </section>\n</template>\n\n<script>\nimport { isActive } from '../util'\nimport DropdownTransition from '@theme/components/DropdownTransition.vue'\n\nexport default {\n  name: 'SidebarGroup',\n  props: ['item', 'open', 'collapsable', 'depth'],\n  components: { DropdownTransition },\n  // ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components\n  beforeCreate () {\n    this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default\n  },\n  methods: { isActive }\n}\n</script>\n\n<style lang=\"stylus\">\n.sidebar-group\n  .sidebar-group\n    padding-left 0.5em\n  &:not(.collapsable)\n    .sidebar-heading:not(.clickable)\n      cursor auto\n      color inherit\n  // refine styles of nested sidebar groups\n  &.is-sub-group\n    padding-left 0\n    & > .sidebar-heading\n      font-size 0.95em\n      line-height 1.4\n      font-weight normal\n      padding-left 2rem\n      &:not(.clickable)\n        opacity 0.5\n    & > .sidebar-group-items\n      padding-left 1rem\n      & > li > .sidebar-link\n        font-size: 0.95em;\n        border-left none\n  &.depth-2\n    & > .sidebar-heading\n      border-left none\n\n.sidebar-heading\n  color $textColor\n  transition color .15s ease\n  cursor pointer\n  font-size 1.1em\n  font-weight bold\n  // text-transform uppercase\n  padding 0.35rem 1.5rem 0.35rem 1.25rem\n  width 100%\n  box-sizing border-box\n  margin 0\n  border-left 0.25rem solid transparent\n  &.open, &:hover\n    color inherit\n  .arrow\n    position relative\n    top -0.12em\n    left 0.5em\n  &.clickable\n    &.active\n      font-weight 600\n      color $accentColor\n      border-left-color $accentColor\n    &:hover\n      color $accentColor\n\n.sidebar-group-items\n  transition height .1s ease-out\n  font-size 0.95em\n  overflow hidden\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/SidebarLink.vue",
    "content": "<script>\nimport { isActive, hashRE, groupHeaders } from '@theme/util'\n\nexport default {\n  functional: true,\n\n  props: ['item', 'sidebarDepth'],\n\n  render (h,\n    {\n      parent: {\n        $page,\n        $site,\n        $route,\n        $themeConfig,\n        $themeLocaleConfig\n      },\n      props: {\n        item,\n        sidebarDepth\n      }\n    }) {\n    // use custom active class matching logic\n    // due to edge case of paths ending with / + hash\n    const selfActive = isActive($route, item.path)\n    // for sidebar: auto pages, a hash link should be active if one of its child\n    // matches\n    const active = item.type === 'auto'\n      ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))\n      : selfActive\n    const link = item.type === 'external'\n      ? renderExternal(h, item.path, item.title || item.path)\n      : renderLink(h, item.path, item.title || item.path, active)\n\n    const maxDepth = [\n      $page.frontmatter.sidebarDepth,\n      sidebarDepth,\n      $themeLocaleConfig.sidebarDepth,\n      $themeConfig.sidebarDepth,\n      1\n    ].find(depth => depth !== undefined);\n\n    const displayAllHeaders = $themeLocaleConfig.displayAllHeaders\n      || $themeConfig.displayAllHeaders\n\n    if (item.type === 'auto') {\n      return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]\n    } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {\n      const children = groupHeaders(item.headers)\n      return [link, renderChildren(h, children, item.path, $route, maxDepth)]\n    } else {\n      return link\n    }\n  }\n}\n\nfunction renderLink (h, to, text, active) {\n  return h('router-link', {\n    props: {\n      to,\n      activeClass: '',\n      exactActiveClass: ''\n    },\n    class: {\n      active,\n      'sidebar-link': true\n    }\n  }, text)\n}\n\nfunction renderChildren (h, children, path, route, maxDepth, depth = 1) {\n  if (!children || depth > maxDepth) return null\n  return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {\n    const active = isActive(route, path + '#' + c.slug)\n    return h('li', { class: 'sidebar-sub-header' }, [\n      renderLink(h, path + '#' + c.slug, c.title, active),\n      renderChildren(h, c.children, path, route, maxDepth, depth + 1)\n    ])\n  }))\n}\n\nfunction renderExternal (h, to, text) {\n  return h('a', {\n    attrs: {\n      href: to,\n      target: '_blank',\n      rel: 'noopener noreferrer'\n    },\n    class: {\n      'sidebar-link': true\n    }\n  }, [text, h('OutboundLink')])\n}\n</script>\n\n<style lang=\"stylus\">\n.sidebar .sidebar-sub-headers\n  padding-left 1rem\n  font-size 0.95em\n\na.sidebar-link\n  font-size 1em\n  font-weight 400\n  display inline-block\n  color $textColor\n  border-left 0.25rem solid transparent\n  padding 0.35rem 1rem 0.35rem 1.25rem\n  line-height 1.4\n  width: 100%\n  box-sizing: border-box\n  &:hover\n    color $accentColor\n  &.active\n    font-weight 600\n    color $accentColor\n    border-left-color $accentColor\n  .sidebar-group &\n    padding-left 2rem\n  .sidebar-sub-headers &\n    padding-top 0.25rem\n    padding-bottom 0.25rem\n    border-left none\n    &.active\n      font-weight 500\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/components/SidebarLinks.vue",
    "content": "<template>\n  <ul\n    class=\"sidebar-links\"\n    v-if=\"items.length\"\n  >\n    <li v-for=\"(item, i) in items\" :key=\"i\">\n      <SidebarGroup\n        v-if=\"item.type === 'group'\"\n        :item=\"item\"\n        :open=\"i === openGroupIndex\"\n        :collapsable=\"item.collapsable || item.collapsible\"\n        :depth=\"depth\"\n        @toggle=\"toggleGroup(i)\"\n      />\n      <SidebarLink\n        v-else\n        :sidebarDepth=\"sidebarDepth\"\n        :item=\"item\"\n      />\n    </li>\n  </ul>\n</template>\n\n<script>\nimport SidebarGroup from '@theme/components/SidebarGroup.vue'\nimport SidebarLink from '@theme/components/SidebarLink.vue'\nimport { isActive } from '../util'\n\nexport default {\n  name: 'SidebarLinks',\n\n  components: { SidebarGroup, SidebarLink },\n\n  props: [\n    'items',\n    'depth',  // depth of current sidebar links\n    'sidebarDepth' // depth of headers to be extracted\n  ],\n\n  data () {\n    return {\n      openGroupIndex: 0\n    }\n  },\n\n  created () {\n    this.refreshIndex()\n  },\n\n  watch: {\n    '$route' () {\n      this.refreshIndex()\n    }\n  },\n\n  methods: {\n    refreshIndex () {\n      const index = resolveOpenGroupIndex(\n        this.$route,\n        this.items\n      )\n      if (index > -1) {\n        this.openGroupIndex = index\n      }\n    },\n\n    toggleGroup (index) {\n      this.openGroupIndex = index === this.openGroupIndex ? -1 : index\n    },\n\n    isActive (page) {\n      return isActive(this.$route, page.regularPath)\n    }\n  }\n}\n\nfunction resolveOpenGroupIndex (route, items) {\n  for (let i = 0; i < items.length; i++) {\n    const item = items[i]\n    if (descendantIsActive(route, item)) {\n      return i\n    }\n  }\n  return -1\n}\n\nfunction descendantIsActive (route, item) {\n  if (item.type === 'group') {\n    return item.children.some(child => {\n      if (child.type === 'group') {\n        return descendantIsActive(route, child)\n      } else {\n        return child.type === 'page' && isActive(route, child.path)\n      }\n    })\n  }\n  return false\n}\n</script>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/global-components/Badge.vue",
    "content": "<script>\nexport default {\n  functional: true,\n  props: {\n    type: {\n      type: String,\n      default: 'tip'\n    },\n    text: String,\n    vertical: {\n      type: String,\n      default: 'top'\n    }\n  },\n  render (h, { props, slots }) {\n    return h('span', {\n      class: ['badge', props.type],\n      style: {\n        verticalAlign: props.vertical\n      }\n    }, props.text || slots().default)\n  }\n}\n</script>\n\n<style lang=\"stylus\" scoped>\n.badge\n  display inline-block\n  font-size 14px\n  height 18px\n  line-height 18px\n  border-radius 3px\n  padding 0 6px\n  color white\n  background-color #42b983\n  &.tip, &.green\n    background-color #42b983\n  &.error\n    background-color #DA5961 //#f66\n  &.warning, &.warn, &.yellow\n    background-color darken(#ffe564, 35%)\n  & + &\n    margin-left 5px\n</style>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/index.js",
    "content": "const path = require('path')\n\n// Theme API.\nmodule.exports = (options, ctx) => ({\n  alias() {\n    const { themeConfig, siteConfig } = ctx\n    // resolve algolia\n    const isAlgoliaSearch = (\n      themeConfig.algolia\n      || Object.keys(siteConfig.locales && themeConfig.locales || {})\n        .some(base => themeConfig.locales[base].algolia)\n    )\n    return {\n      '@AlgoliaSearchBox': isAlgoliaSearch\n        ? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue')\n        : path.resolve(__dirname, 'noopModule.js')\n    }\n  },\n\n  plugins: [\n    ['@vuepress/active-header-links', options.activeHeaderLinks],\n    '@vuepress/search',\n    '@vuepress/plugin-nprogress',\n    ['container', {\n      type: 'tip',\n      defaultTitle: {\n        '/zh/': '提示'\n      }\n    }],\n    ['container', {\n      type: 'warning',\n      defaultTitle: {\n        '/zh/': '注意'\n      }\n    }],\n    ['container', {\n      type: 'danger',\n      defaultTitle: {\n        '/zh/': '警告'\n      }\n    }],\n    ['container', {\n      type: 'details',\n      before: info => `<details class=\"custom-block details\">${info ? `<summary>${info}</summary>` : ''}\\n`,\n      after: () => '</details>\\n'\n    }]\n  ]\n})\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/layouts/404.vue",
    "content": "<template>\n  <div class=\"theme-container\">\n    <div class=\"theme-default-content\">\n      <h1>404</h1>\n      <blockquote>{{ getMsg() }}</blockquote>\n      <router-link to=\"/\">Take me home.</router-link>\n    </div>\n  </div>\n</template>\n\n<script>\nconst msgs = [\n  `There's nothing here.`,\n  `How did we get here?`,\n  `That's a Four-Oh-Four.`,\n  `Looks like we've got some broken links.`\n]\n\nexport default {\n  methods: {\n    getMsg () {\n      return msgs[Math.floor(Math.random() * msgs.length)]\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/layouts/Layout.vue",
    "content": "<template>\n  <div\n    class=\"theme-container\"\n    :class=\"pageClasses\"\n    @touchstart=\"onTouchStart\"\n    @touchend=\"onTouchEnd\"\n  >\n    <Navbar\n      v-if=\"shouldShowNavbar\"\n      @toggle-sidebar=\"toggleSidebar\"\n    />\n\n    <div\n      class=\"sidebar-mask\"\n      @click=\"toggleSidebar(false)\"\n    ></div>\n\n    <Sidebar\n      :items=\"sidebarItems\"\n      @toggle-sidebar=\"toggleSidebar\"\n    >\n      <slot\n        name=\"sidebar-top\"\n        slot=\"top\"\n      />\n      <slot\n        name=\"sidebar-bottom\"\n        slot=\"bottom\"\n      />\n    </Sidebar>\n\n    <Home v-if=\"$page.frontmatter.home\"/>\n\n    <Page\n      v-else\n      :sidebar-items=\"sidebarItems\"\n    >\n      <slot\n        name=\"page-top\"\n        slot=\"top\"\n      />\n      <slot\n        name=\"page-bottom\"\n        slot=\"bottom\"\n      />\n    </Page>\n  </div>\n</template>\n\n<script>\nimport Home from '@theme/components/Home.vue'\nimport Download from '@theme/components/Download.vue'\nimport Navbar from '@theme/components/Navbar.vue'\nimport Page from '@theme/components/Page.vue'\nimport Sidebar from '@theme/components/Sidebar.vue'\nimport { resolveSidebarItems } from '../util'\n\nexport default {\n  components: { Home, Download, Page, Sidebar, Navbar },\n\n  data () {\n    return {\n      isSidebarOpen: false\n    }\n  },\n\n  computed: {\n    shouldShowNavbar () {\n      const { themeConfig } = this.$site\n      const { frontmatter } = this.$page\n      if (\n        frontmatter.navbar === false\n        || themeConfig.navbar === false) {\n        return false\n      }\n      return (\n        this.$title\n        || themeConfig.logo\n        || themeConfig.repo\n        || themeConfig.nav\n        || this.$themeLocaleConfig.nav\n      )\n    },\n\n    shouldShowSidebar () {\n      const { frontmatter } = this.$page\n      return (\n        !frontmatter.home\n        && !frontmatter.download\n        && frontmatter.sidebar !== false\n        && this.sidebarItems.length\n      )\n    },\n\n    sidebarItems () {\n      return resolveSidebarItems(\n        this.$page,\n        this.$page.regularPath,\n        this.$site,\n        this.$localePath\n      )\n    },\n\n    pageClasses () {\n      const userPageClass = this.$page.frontmatter.pageClass\n      return [\n        {\n          'no-navbar': !this.shouldShowNavbar,\n          'sidebar-open': this.isSidebarOpen,\n          'no-sidebar': !this.shouldShowSidebar\n        },\n        userPageClass\n      ]\n    }\n  },\n\n  mounted () {\n    this.$router.afterEach(() => {\n      this.isSidebarOpen = false\n    })\n  },\n\n  methods: {\n    toggleSidebar (to) {\n      this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen\n      this.$emit('toggle-sidebar', this.isSidebarOpen)\n    },\n\n    // side swipe\n    onTouchStart (e) {\n      this.touchStart = {\n        x: e.changedTouches[0].clientX,\n        y: e.changedTouches[0].clientY\n      }\n    },\n\n    onTouchEnd (e) {\n      const dx = e.changedTouches[0].clientX - this.touchStart.x\n      const dy = e.changedTouches[0].clientY - this.touchStart.y\n      if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {\n        if (dx > 0 && this.touchStart.x <= 80) {\n          this.toggleSidebar(true)\n        } else {\n          this.toggleSidebar(false)\n        }\n      }\n    }\n  }\n}\n</script>\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/noopModule.js",
    "content": "export default {}\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/arrow.styl",
    "content": "@require './config'\n\n.arrow\n  display inline-block\n  width 0\n  height 0\n  &.up\n    border-left 4px solid transparent\n    border-right 4px solid transparent\n    border-bottom 6px solid $arrowBgColor\n  &.down\n    border-left 4px solid transparent\n    border-right 4px solid transparent\n    border-top 6px solid $arrowBgColor\n  &.right\n    border-top 4px solid transparent\n    border-bottom 4px solid transparent\n    border-left 6px solid $arrowBgColor\n  &.left\n    border-top 4px solid transparent\n    border-bottom 4px solid transparent\n    border-right 6px solid $arrowBgColor\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/code.styl",
    "content": "{$contentClass}\n  code\n    color lighten($textColor, 20%)\n    padding 0.25rem 0.5rem\n    margin 0\n    font-size 0.85em\n    background-color rgba(27,31,35,0.05)\n    border-radius 3px\n    .token\n      &.deleted\n        color #EC5975\n      &.inserted\n        color $accentColor\n\n{$contentClass}\n  pre, pre[class*=\"language-\"]\n    line-height 1.4\n    padding 1.25rem 1.5rem\n    margin 0.85rem 0\n    background-color $codeBgColor\n    border-radius 6px\n    overflow auto\n    code\n      color #fff\n      padding 0\n      background-color transparent\n      border-radius 0\n\ndiv[class*=\"language-\"]\n  position relative\n  background-color $codeBgColor\n  border-radius 6px\n  .highlight-lines\n    user-select none\n    padding-top 1.3rem\n    position absolute\n    top 0\n    left 0\n    width 100%\n    line-height 1.4\n    .highlighted\n      background-color rgba(0, 0, 0, 66%)\n  pre, pre[class*=\"language-\"]\n    background transparent\n    position relative\n    z-index 1\n  &::before\n    position absolute\n    z-index 3\n    top 0.8em\n    right 1em\n    font-size 0.75rem\n    color rgba(255, 255, 255, 0.4)\n  &:not(.line-numbers-mode)\n    .line-numbers-wrapper\n      display none\n  &.line-numbers-mode\n    .highlight-lines .highlighted\n        position relative\n        &:before\n          content ' '\n          position absolute\n          z-index 3\n          left 0\n          top 0\n          display block\n          width $lineNumbersWrapperWidth\n          height 100%\n          background-color rgba(0, 0, 0, 66%)\n    pre\n      padding-left $lineNumbersWrapperWidth + 1 rem\n      vertical-align middle\n    .line-numbers-wrapper\n      position absolute\n      top 0\n      width $lineNumbersWrapperWidth\n      text-align center\n      color rgba(255, 255, 255, 0.3)\n      padding 1.25rem 0\n      line-height 1.4\n      br\n        user-select none\n      .line-number\n        position relative\n        z-index 4\n        user-select none\n        font-size 0.85em\n    &::after\n      content ''\n      position absolute\n      z-index 2\n      top 0\n      left 0\n      width $lineNumbersWrapperWidth\n      height 100%\n      border-radius 6px 0 0 6px\n      border-right 1px solid rgba(0, 0, 0, 66%)\n      background-color $codeBgColor\n\n\nfor lang in $codeLang\n  div{'[class~=\"language-' + lang + '\"]'}\n    &:before\n      content ('' + lang)\n\ndiv[class~=\"language-javascript\"]\n  &:before\n    content \"js\"\n\ndiv[class~=\"language-typescript\"]\n  &:before\n    content \"ts\"\n\ndiv[class~=\"language-markup\"]\n  &:before\n    content \"html\"\n\ndiv[class~=\"language-markdown\"]\n  &:before\n    content \"md\"\n\ndiv[class~=\"language-json\"]:before\n  content \"json\"\n\ndiv[class~=\"language-ruby\"]:before\n  content \"rb\"\n\ndiv[class~=\"language-python\"]:before\n  content \"py\"\n\ndiv[class~=\"language-bash\"]:before\n  content \"sh\"\n\ndiv[class~=\"language-php\"]:before\n  content \"php\"\n\n@import '~prismjs/themes/prism-tomorrow.css'\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/config.styl",
    "content": "$contentClass = '.theme-default-content'\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/custom-blocks.styl",
    "content": ".custom-block\n  .custom-block-title\n    font-weight 600\n    margin-bottom -0.4rem\n  &.tip, &.warning, &.danger\n    padding .1rem 1.5rem\n    border-left-width .5rem\n    border-left-style solid\n    margin 1rem 0\n  &.tip\n    background-color #f3f5f7\n    border-color #42b983\n  &.warning\n    background-color rgba(255,229,100,.3)\n    border-color darken(#ffe564, 35%)\n    color darken(#ffe564, 70%)\n    .custom-block-title\n      color darken(#ffe564, 50%)\n    a\n      color $textColor\n  &.danger\n    background-color #ffe6e6\n    border-color darken(red, 20%)\n    color darken(red, 70%)\n    .custom-block-title\n      color darken(red, 40%)\n    a\n      color $textColor\n  &.details\n    display block\n    position relative\n    border-radius 2px\n    margin 1.6em 0\n    padding 1.6em\n    background-color #eee\n    h4\n      margin-top 0\n    figure, p\n      &:last-child\n        margin-bottom 0\n        padding-bottom 0\n    summary\n      outline none\n      cursor pointer\n\n\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/index.styl",
    "content": "@require './config'\n@require './code'\n@require './custom-blocks'\n@require './arrow'\n@require './wrapper'\n@require './toc'\n\ncode\n  overflow: auto\n  word-wrap:break-word\n\nbody\n  font-family Roboto, sans-serif\n\nbody:lang(zh-hans)\n  font-family Roboto, 'Noto Sans SC', sans-serif\n\nbody:lang(zh-hant)\n  font-family Roboto, 'Noto Sans TC', sans-serif\n\nem\n  font-style italic\n  font-variation-settings \"ital\" 1\n\nhtml, body\n  padding 0\n  margin 0\n  background-color #fff\n\nbody\n  -webkit-font-smoothing antialiased\n  -moz-osx-font-smoothing grayscale\n  font-size 16px\n  color $textColor\n\n.page\n  padding-left $sidebarWidth\n\n.navbar\n  position fixed\n  z-index 20\n  top 0\n  left 0\n  right 0\n  height $navbarHeight\n  background-color #fff\n  box-sizing border-box\n  border-bottom 1px solid $borderColor\n\n.sidebar-mask\n  position fixed\n  z-index 9\n  top 0\n  left 0\n  width 100vw\n  height 100vh\n  display none\n\n.sidebar\n  font-size 16px\n  background-color #fff\n  width $sidebarWidth\n  position fixed\n  z-index 10\n  margin 0\n  top $navbarHeight\n  left 0\n  bottom 0\n  box-sizing border-box\n  border-right 1px solid $borderColor\n  overflow-y auto\n\n{$contentClass}:not(.custom)\n  @extend $wrapper\n  > *:first-child\n    margin-top $navbarHeight\n\n  a:hover\n    text-decoration underline\n\n  p.demo\n    padding 1rem 1.5rem\n    border 1px solid #ddd\n    border-radius 4px\n\n  img\n    max-width 100%\n\n{$contentClass}.custom\n  padding 0\n  margin 0\n\n  img\n    max-width 100%\n\na\n  font-weight 500\n  color $accentColor\n  text-decoration none\n\np a code\n  font-weight 400\n  color $accentColor\n\nkbd\n  background #eee\n  border solid 0.15rem #ddd\n  border-bottom solid 0.25rem #ddd\n  border-radius 0.15rem\n  padding 0 0.15em\n\nblockquote\n  font-size 1rem\n  color #999;\n  border-left .2rem solid #dfe2e5\n  margin 1rem 0\n  padding .25rem 0 .25rem 1rem\n\n  & > p\n    margin 0\n\nul, ol\n  padding-left 1.2em\n\nstrong\n  font-weight 600\n\nh1, h2, h3, h4, h5, h6\n  font-weight 600\n  line-height 1.25\n\n  {$contentClass}:not(.custom) > &\n    margin-top (0.5rem - $navbarHeight)\n    padding-top ($navbarHeight + 1rem)\n    margin-bottom 0\n\n    &:first-child\n      margin-top -1.5rem\n      margin-bottom 1rem\n\n      + p, + pre, + .custom-block\n        margin-top 2rem\n\n  &:hover .header-anchor\n    opacity: 1\n\nh1\n  font-size 2.2rem\n\nh2\n  font-size 1.65rem\n  padding-bottom .3rem\n  border-bottom 1px solid $borderColor\n\nh3\n  font-size 1.35rem\n\na.header-anchor\n  font-size 0.85em\n  float left\n  margin-left -0.87em\n  padding-right 0.23em\n  margin-top 0.125em\n  opacity 0\n\n  &:hover\n    text-decoration none\n\ncode, kbd, .line-number\n  font-family 'Roboto Mono', 'Source Code Pro BDC', monospace\n\np, ul, ol\n  line-height 1.7\n\nhr\n  border 0\n  border-top 1px solid $borderColor\n\ntable\n  border-collapse collapse\n  margin 1rem 0\n  display: block\n  overflow-x: auto\n\ntr\n  border-top 1px solid #dfe2e5\n\n  &:nth-child(2n)\n    background-color #f6f8fa\n\nth, td\n  border 1px solid #dfe2e5\n  padding .6em 1em\n\n.theme-container\n  &.sidebar-open\n    .sidebar-mask\n      display: block\n\n  &.no-navbar\n    {$contentClass}:not(.custom) > h1, h2, h3, h4, h5, h6\n      margin-top 1.5rem\n      padding-top 0\n\n    .sidebar\n      top 0\n\n\n@media (min-width: ($MQMobile + 1px))\n  .theme-container.no-sidebar\n    .sidebar\n      display none\n\n    .page\n      padding-left 0\n\n@require 'mobile.styl'\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/mobile.styl",
    "content": "@require './config'\n\n$mobileSidebarWidth = $sidebarWidth * 0.82\n\n// narrow desktop / iPad\n@media (max-width: $MQNarrow)\n  .sidebar\n    font-size 15px\n    width $mobileSidebarWidth\n  .page\n    padding-left $mobileSidebarWidth\n\n// wide mobile\n@media (max-width: $MQMobile)\n  .sidebar\n    top 0\n    padding-top $navbarHeight\n    transform translateX(-100%)\n    transition transform .2s ease\n  .page\n    padding-left 0\n  .theme-container\n    &.sidebar-open\n      .sidebar\n        transform translateX(0)\n    &.no-navbar\n      .sidebar\n        padding-top: 0\n\n// narrow mobile\n@media (max-width: $MQMobileNarrow)\n  h1\n    font-size 1.9rem\n  {$contentClass}\n    div[class*=\"language-\"]\n      margin 0.85rem -1.5rem\n      border-radius 0\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/palette.styl",
    "content": "$accentColor = #01579B\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/toc.styl",
    "content": ".table-of-contents\n  .badge\n    vertical-align middle\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/styles/wrapper.styl",
    "content": "$wrapper\n  max-width $contentWidth\n  margin 0 auto\n  padding 2rem 2.5rem\n  @media (max-width: $MQNarrow)\n    padding 2rem\n  @media (max-width: $MQMobileNarrow)\n    padding 1.5rem\n\n"
  },
  {
    "path": "storage_redirect/.vuepress/theme/util/index.js",
    "content": "export const hashRE = /#.*$/\nexport const extRE = /\\.(md|html)$/\nexport const endingSlashRE = /\\/$/\nexport const outboundRE = /^[a-z]+:/i\n\nexport function normalize (path) {\n  return decodeURI(path)\n    .replace(hashRE, '')\n    .replace(extRE, '')\n}\n\nexport function getHash (path) {\n  const match = path.match(hashRE)\n  if (match) {\n    return match[0]\n  }\n}\n\nexport function isExternal (path) {\n  return outboundRE.test(path)\n}\n\nexport function isMailto (path) {\n  return /^mailto:/.test(path)\n}\n\nexport function isTel (path) {\n  return /^tel:/.test(path)\n}\n\nexport function ensureExt (path) {\n  if (isExternal(path)) {\n    return path\n  }\n  const hashMatch = path.match(hashRE)\n  const hash = hashMatch ? hashMatch[0] : ''\n  const normalized = normalize(path)\n\n  if (endingSlashRE.test(normalized)) {\n    return path\n  }\n  return normalized + '.html' + hash\n}\n\nexport function isActive (route, path) {\n  const routeHash = route.hash\n  const linkHash = getHash(path)\n  if (linkHash && routeHash !== linkHash) {\n    return false\n  }\n  const routePath = normalize(route.path)\n  const pagePath = normalize(path)\n  return routePath === pagePath\n}\n\nexport function resolvePage (pages, rawPath, base) {\n  if (isExternal(rawPath)) {\n    return {\n      type: 'external',\n      path: rawPath\n    }\n  }\n  if (base) {\n    rawPath = resolvePath(rawPath, base)\n  }\n  const path = normalize(rawPath)\n  for (let i = 0; i < pages.length; i++) {\n    if (normalize(pages[i].regularPath) === path) {\n      return Object.assign({}, pages[i], {\n        type: 'page',\n        path: ensureExt(pages[i].path)\n      })\n    }\n  }\n  console.error(`[vuepress] No matching page found for sidebar item \"${rawPath}\"`)\n  return {}\n}\n\nfunction resolvePath (relative, base, append) {\n  const firstChar = relative.charAt(0)\n  if (firstChar === '/') {\n    return relative\n  }\n\n  if (firstChar === '?' || firstChar === '#') {\n    return base + relative\n  }\n\n  const stack = base.split('/')\n\n  // remove trailing segment if:\n  // - not appending\n  // - appending to trailing slash (last segment is empty)\n  if (!append || !stack[stack.length - 1]) {\n    stack.pop()\n  }\n\n  // resolve relative path\n  const segments = relative.replace(/^\\//, '').split('/')\n  for (let i = 0; i < segments.length; i++) {\n    const segment = segments[i]\n    if (segment === '..') {\n      stack.pop()\n    } else if (segment !== '.') {\n      stack.push(segment)\n    }\n  }\n\n  // ensure leading slash\n  if (stack[0] !== '') {\n    stack.unshift('')\n  }\n\n  return stack.join('/')\n}\n\n/**\n * @param { Page } page\n * @param { string } regularPath\n * @param { SiteData } site\n * @param { string } localePath\n * @returns { SidebarGroup }\n */\nexport function resolveSidebarItems (page, regularPath, site, localePath) {\n  const { pages, themeConfig } = site\n\n  const localeConfig = localePath && themeConfig.locales\n    ? themeConfig.locales[localePath] || themeConfig\n    : themeConfig\n\n  const pageSidebarConfig = page.frontmatter.sidebar || localeConfig.sidebar || themeConfig.sidebar\n  if (pageSidebarConfig === 'auto') {\n    return resolveHeaders(page)\n  }\n\n  const sidebarConfig = localeConfig.sidebar || themeConfig.sidebar\n  if (!sidebarConfig) {\n    return []\n  } else {\n    const { base, config } = resolveMatchingConfig(regularPath, sidebarConfig)\n    return config\n      ? config.map(item => resolveItem(item, pages, base))\n      : []\n  }\n}\n\n/**\n * @param { Page } page\n * @returns { SidebarGroup }\n */\nfunction resolveHeaders (page) {\n  const headers = groupHeaders(page.headers || [])\n  return [{\n    type: 'group',\n    collapsable: false,\n    title: page.title,\n    path: null,\n    children: headers.map(h => ({\n      type: 'auto',\n      title: h.title,\n      basePath: page.path,\n      path: page.path + '#' + h.slug,\n      children: h.children || []\n    }))\n  }]\n}\n\nexport function groupHeaders (headers) {\n  // group h3s under h2\n  headers = headers.map(h => Object.assign({}, h))\n  let lastH2\n  headers.forEach(h => {\n    if (h.level === 2) {\n      lastH2 = h\n    } else if (lastH2) {\n      (lastH2.children || (lastH2.children = [])).push(h)\n    }\n  })\n  return headers.filter(h => h.level === 2)\n}\n\nexport function resolveNavLinkItem (linkItem) {\n  return Object.assign(linkItem, {\n    type: linkItem.items && linkItem.items.length ? 'links' : 'link'\n  })\n}\n\n/**\n * @param { Route } route\n * @param { Array<string|string[]> | Array<SidebarGroup> | [link: string]: SidebarConfig } config\n * @returns { base: string, config: SidebarConfig }\n */\nexport function resolveMatchingConfig (regularPath, config) {\n  if (Array.isArray(config)) {\n    return {\n      base: '/',\n      config: config\n    }\n  }\n  for (const base in config) {\n    if (ensureEndingSlash(regularPath).indexOf(encodeURI(base)) === 0) {\n      return {\n        base,\n        config: config[base]\n      }\n    }\n  }\n  return {}\n}\n\nfunction ensureEndingSlash (path) {\n  return /(\\.html|\\/)$/.test(path)\n    ? path\n    : path + '/'\n}\n\nfunction resolveItem (item, pages, base, groupDepth = 1) {\n  if (typeof item === 'string') {\n    return resolvePage(pages, item, base)\n  } else if (Array.isArray(item)) {\n    return Object.assign(resolvePage(pages, item[0], base), {\n      title: item[1]\n    })\n  } else {\n    if (groupDepth > 3) {\n      console.error(\n        '[vuepress] detected a too deep nested sidebar group.'\n      )\n    }\n    const children = item.children || []\n    if (children.length === 0 && item.path) {\n      return Object.assign(resolvePage(pages, item.path, base), {\n        title: item.title\n      })\n    }\n    return {\n      type: 'group',\n      path: item.path,\n      title: item.title,\n      sidebarDepth: item.sidebarDepth,\n      children: children.map(child => resolveItem(child, pages, base, groupDepth + 1)),\n      collapsable: item.collapsable !== false\n    }\n  }\n}\n"
  },
  {
    "path": "storage_redirect/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: Download\nactionLink: /download.html\nsecondaryActionText: Learn more\nsecondaryActionLink: /guide/\nfeatures:\n- title: No more abusing\n  details: Enable isolation for specified apps, they will only have access to user-specified folders.\n- title: Bring back clean storage\n  details: Bad apps can never create tons of folders; useful files, media, etc. are saved to standard folders according to user-defined rules.\n- title: Monitor file operations\n  details: Monitored file operations of apps, learn which file is used.\nfooter: Copyright © 2020 RikkaApps\n---"
  },
  {
    "path": "storage_redirect/changelog.md",
    "content": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- Fixed an issue that on Android 10+, \"Export isolated files & Redirect system providers\" option was not displayed for apps not requesting for write storage permission\n  \n  On Android 10+, the Android system allows eligible apps (**even if it doesn't request any permissions**) to write to standard folders (eligible apps are those whose target API is 30 or above, or whose target API is 29 and has adapted to Scoped Storage). This option is meaningful for such applications.\n\n## 8.4.2 (2023-03-22)\n\n- Fix the problem that from version 8.4.0, app is unable to use if \"Dark theme\" option is not set to \"Follow system\"\n\n## 8.4.1 (2023-03-17)\n\n- Fix the problem that in the last version, entering app list will crash the app if Enhance mode is not used\n\n## 8.4.0 (2023-03-12)\n\n- Fixed an issue where an app with an export rule (whether the rule is enabled or not) would be force stopped on first launch of the core service\n- [For Android 10 and earlier versions only] File Monitor no longer requires Shamiko to be installed (but please note that the hidden solution is still necessary, so File Monitor will be turned off after the update)\n- Fixed the problem that apps which only requests Android 13 new permissions was judged as not request any permissions (the previous version did not fix it properly)\n- For Chinese, Japanese and Korean language users, if the system does not provide a Medium (500) weight font, it will use the simulation implementation\n\n## 8.3.0 (2023-01-03)\n\n- Fixed the problem that apps that did not request any permissions above Android 11 were skipped (on Android 11 and above, apps without any permissions can also write files and folders in standard folders)\n- Fixed the problem that apps which only requests Android 13 new permissions was judged as not request any permissions\n\n## 8.2.2 (2022-12-05)\n\n- Add user approval step before requesting online rule\n\n## 8.2.1 (2022-11-22)\n\n- Better Android 13 support\n\n## 8.1.0 (2022-10-15)\n\n- Ensure apps with `Shared user ID` will use a consistent isolated storage folder\n- Fix some unnecessary checks are done when using the Zygisk version of the enhance module\n- An early fix for an issue that would prevent \"limited mode\" from being available in the next Android version\n\n## 8.0.0 (2022-08-21)\n\n- New File monitor implemention\n- Disable \"Fix reanme\" which is uncessary on Android 10 and above\n- Fix the problem that reinstalled app which has \"uninstall but keep data\" before is not displayed\n\nThe difference between old and new File monitor:\n\nOld:\n- Need to inject into all are processes (which means this may be detected, especially Zygisk version)\n- Can't record operations performed by syscalls and native libraries loaded later\n\nNew:\n- No need to inject app processes\n- Can record operations that were previously unrecordable, but cannot record operations performed by isolated apps\n- Requires Android 11 and above (if the device runs Android 10 or older, the old version will still be used)\n\n## 7.5.3 (2022-06-14)\n\n- Fix v7.5.2 is broken on Android 10 and below\n\n## 7.5.2 (2022-06-14)\n\n- Fix a problem where \"Handle system providers\" causing some apps unable to access files that were already been set as accessible\n\n## 7.5.1 (2022-06-09)\n\n- Fix not work on Android 13 Beta 3\n\n## 7.5.0 (2022-05-20)\n\n- Enhance module v27: Restore \"Access folders from other apps\" on deivces without sdcardfs\n- Some UI adjustments\n\n## 7.3.4 (2022-05-06)\n\n- Remake \"Backup & restore\" feature (old backups are still supported, but it's highly recommended to recreate the backup file with the new app)\n- Try to fix broken database file breaks \"File monitor\" feature\n- Switch to Material Design 3 (Material You)\n\n## 7.1.0 (2022-02-22)\n\n- Supports Android 13 DP1 (however, based on experience, DP1 is a very early version and the app will most likely not work again due to changes in DP2)\n- Enhanced Mode 26.1.0: Fixed File monitor feature causing Download Manager to break on some OnePlus (OPPO) devices\n\n## 7.0.0 (2022-01-29)\n\n- Enhanced mode support Zygisk\n- Fix the problem that apps installed only in non-primary user cannot be listed\n\n## 6.4.0 (2021-12-13)\n\n- Fix the problem that when creating export rules for apps with `Shared user ID` on Android 11+, source path cannot be choosen (no folder is shown)\n- Some UI adjustments\n\n## 6.3.0 (2021-11-14)\n\n- Correct the description about apps on Android 11 can write files to standard folders without permission\n- Some UI issue fix\n- Target SDK 31\n\n## 6.2.0 (2021-10-14)\n\n- Significantly improve the performance of FileMonitor especially for users have a large amount of records\n- Fix the problem that FileMonitor may not able to show all records when the filter is set\n- Fix the problem that FileMonitor may not able to disaply records from \"MediaStore\"\n- Correct the description about apps with target API 30 or higher on Android 11 that can write files to standard folders without permission\n\n## 6.1.10 (2021-09-16)\n\n- On Android 11+, allow setting folders in `Android` folder as \"Accessible folders\" for apps like MediaStore\n\n## 6.1.9 (2021-09-03)\n\n- Fix the problem that on devices without `sdcardfs`, app may not be able to access the folder used by \"Export isolated files\" rule\n- Fix a UI bug\n\n## 6.1.8 (2021-08-29)\n\n- Recreate the database of File monitor when it is broken\n- Fix a internal problem that will cause the crash of the core service\n\n## 6.1.5 (2021-08-12)\n\n- Handle system server restart correctly\n\n## 6.1.4 (2021-07-14)\n\n- Fix the problem that, from v6.1.0, apps with `Shared user ID` may not be isolated correctly\n- Fix cannot add a same \"Allow access files from other app\" rule to different users\n- Fix the problem that selected but non-exist folder will not be shown in \"Accessible folders\" picker\n\n## 6.1.0 (2021-06-30)\n\n- Allow to isolate apps with only read storage permission\n- Allow to isolate apps without storage permission on Android 10+ under enhanced mode\n  \n  Apps without storage permissions can write media (picture, video, music) files to standard folders through Media Store. There are apps persist its data by generating fake media files.\n\n- Fix the problem that the enhancement module is sometimes displayed as not installed\n- Fix crash on x86 devices\n- Hide some apps (apps without components, apps without code, overlay apps) from the app list (such apps cannot run by themselves, isolate them is meaningless)\n\n## 6.0.2 (2021-06-27)\n\n- Enhancement module v25:\n  - Apps can no longer use non-accessible folders through Media Storage (old versions can't handle the new method added from Android 10)\n  - File monitor can record the event of apps use Media Storage\n  - Redo \"the Media Storage part\" from scratch, having much better performance and compatibility than before\n- Improved File monitor UI\n- Fix Gallery preview will crash the core service from Android 12 Beta 1\n- Due to the massive changes of module v25, old versions of the enhancement module is no longer supported\n- Remove some migration codes for super old versions\n- Fix crash on x86 devices\n\n## 5.4.5 (2021-05-21)\n\n- Limited mode (Enhancement module not installed) works on Android 12 Beta 1\n- Add \"Exclude private files\" option for File monitor\n\n## 5.4.3 (2021-05-06)\n\n- Fix the problem that accessible folder templates needs a lot of time to be loaded\n\n## 5.4.1 (2021-05-04)\n\n- Prevent 💩 MIUI's \"Force dark mode\" from breaking app's theme<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI has its own \"Force dark mode\". However it seems that even if the app has provided correct dark theme, MIUI's \"Force dark mode\" will still take effect and finally mess up colors.</sub>\n\n## 5.4.0 (2021-05-03)\n\n- Try to solve the problem that MediaStore on Android 11 or above cannot be isolated (On MIUI, isolate it may be necessary)\n- Add a few mistake-proofing changes for Android 11 or above\n- Record the total number of handled isolated apps\n\n## 5.3.5 (2021-04-28)\n\n- Try to fix a problem that may causes the crash of the core service\n- Hide some apps (apps without components, apps without code, overlay apps) from the app list (such apps cannot run by themselves, isolate them is meaningless)\n\n## 5.3.4 (2021-04-27)\n\n- Fix a problem related to \"Fix app interaction\" that cause isolated apps not working, this problem only happens on few devices\n\n## 5.3.1 (2021-03-27)\n\n- Use [self-compiled libcxx](https://github.com/RikkaW/libcxx-prefab) to reduce the file size (about 300KB reduction)\n- Enhancement module upgrade to Riru 25\n- Adapt to an Android 12 change\n- Report when the enhanced mode is not working properly\n- Solved the problem comes from Android 11 user manually disable fuse\n\n## 5.2.0 (2021-01-27)\n\n- Fix an issue on Android 11 where all functions that require listing files did not work properly for non-primary users\n\n## 5.1.0 (2021-01-19)\n\n- Support start with Sui (https://github.com/RikkaApps/Sui) (Of course due to the high complexity of this app, it really just start)\n- \"File monitor\" can show records from non-primary user now\n\n## 5.0.2 (2020-12-20)\n\n- Fix a problem which may cause apps with `sharedUserId` (called \"App group\" in the app) cannot be isolated\n- When \"Block system remount\" is available, don't automatically allow `OP_REQUEST_INSTALL_PACKAGES` (The reason for doing this before is, the change of `OP_REQUEST_INSTALL_PACKAGES` will trigger system remount, cause isolation become invalid)\n\n## 5.0.1 (2020-12-15)\n\n- Fix the problem that on Android 11, newly added \"Export isolated folders\" rules will not take effect immediately\n\n## 5.0.0 (2020-11-23)\n\n- Support devices published with Android 11 which has `sdcardfs` removed (Pixel 5, Pixel 4a 5G, etc)\n- On Android 11, \"Export isolated folder\" is implemented with `mount` rather than `hard link` (media storage have no permission to access link files)\n- Use binder for all IPC involving `untrusted_app` domain (many things are completely rewritten)\n- Remove almost all traces that indicate the device is rooted\n- Use `/data/adb/storage-isolation` as data folder, you can delete `/data/misc/storage_redirect` if there is no problem\n- It's hard to speak all the changed things 😶\n\n## 4.5.3 (2020-08-20)\n\n- Change the core implementation, solve the problem caused by \"adapt to Android 11 changes\" introduced from the previous version\n- Adapt to changes in Android 11 beta 3\n\n## 4.5.2 (2020-06-19)\n\n- Don't let a weird error<sup>**〔1〕**</sup> crash the whole app\n\n<sub><b>〔1〕</b>An error related to Retrofit + Kotlin coroutines, stacktrace is empty</sub>\n\n## 4.5.0 (2020-06-16)\n\n- Fix the problem that on Android 11, isolate app which starts earlier than user unlock will cause serious problem\n- When \"Enhanced mode\" - \"Block system remount\" option is enabled, storage permission of isolated apps will not be enforced<sup>**〔1〕**</sup>\n- Enhanced mode: \"Block system remount\" now works on Android 11\n- Enhanced mode: \"Fix app interaction\" now works on Android 11\n- Enhanced mode: Remove toast of \"Fix app interaction\" (for the use case of inspection, check logs with tag \"SRHook\")\n- Enhanced mode v22.6: Fix app-level toggle of \"fix app interaction\" not work\n- The title for \"Export isolated files\" rule is customizable\n- Improve the performance of \"App settings\" page\n- \"View gallery\" works on Android 11\n- When the app starts on boot, don't kill process started by Enhanced mode\n- Raise target API version to 30\n- Change the icon\n\n<sub><b>〔1〕</b>Due to user reports, it might cause problems on 💩 systems like MIUI.</sub>\n\n> According to user reports and investigations, \"Fix app interaction\" does not work on some highly modified systems (at least includes 💩 OnePlus). We will switch to a completely different way in the future.\n\n## 4.4.1 (2020-05-01)\n\n- Fix \"File monitor\" page lag\n- Fix display issue of \"Accessible folders\" - \"Files from other apps\"\n\n## 4.4.0 (2020-04-29)\n\n- Fix app interaction: Remove \"startActivity hook\"<sup>**〔1〕**</sup><sup>**〔2〕**</sup>\n- Fix change \"Default isolated storage location\" may wait forever on some situations\n- Correctly implement \"Up\" (the arrow in ActionBar)<sup>**〔3〕**</sup><sup>**〔4〕**</sup> (so sad even some system apps are not doing this right 😰)\n- Fix edge effects for all lists which shows below system bars (almost all apps not doing this right 😋)\n- Hide \"View gallery\" on Android R because it's broken\n\n<sub><b>〔1〕</b>It may cause problems.</sub>\n<br><sub><b>〔2〕</b>On Android 10+, exposing `file` uri will cause crash, garbage apps should have changed. We no longer need to \"help\" them.</sub>\n<br><sub><b>〔3〕</b>According to the <del>ancient</del> guideline, \"Back\" navigates to the previous screen but \"Up\" navigates to the logical up level. For example, enter a deep page of A from B, \"Back\" backs to B while \"Up\" goes to the upper page of A. (This also requires B doing right)</sub>\n<br><sub><b>〔4〕</b>On Android R Developer Preview, Google breaks this \"nobody use thing\", so \"up\" works as \"back\" until Google fix it.</sub>\n\n## 4.3.1 (2020-04-05)\n\n- Add a simpler way to submit rules\n- Fix the problem that unable to add \"Accessible folder\" - \"Folders from other apps\" rule for apps installed in non-primary users\n- Fix some UI bugs\n\n## 4.2.3 (2020-03-24)\n\n- Solve problems when using with \"Freezer\" apps based on `setApplicationHiddenSettingAsUser`\n\n## 4.2.2 (2020-03-22)\n\n- Fix the problem that, in the app settings, online rule loads before accessible folder causing bad experience under bad network\n\n## 4.2.1 (2020-03-21)\n\n- Change the implementation of \"New app notification\" and notifications of \"Export isolated files\" rules. This can workaround 💩 MIUI's system bug<sup>**〔1〕**</sup> and a minor historical issue<sup>**〔2〕**</sup>\n- The version of Enhancement module is now fetched online\n- The app list of \"Accessible folders template\" now support multi-user correctly\n- Add more foolproof design\n\n<sub>**〔1〕** In uncertain situations, MIUI will deserialize (`unparcel`) the `Bundle` in the `Intent` passed by `startActivity` in `system_server`. If the `Bundle` contains a non-system `Parcelable`, deserialization fails and the `Bundle` is broken forever, the app will only receive a blank `Bundle`.</sub>\n<br><sub>**〔2〕** If the data structure changes and the core service has not been updated after installing a new version of the app, the app will crash when showing notification.</sub>\n\n## 4.2.0 (2020-03-14)\n\n- Enabling isolation for system apps which starts early will no longer cause problems (but, just in case, you still need to [be prepared](./guide/enhanced_mode/install.html#unable-to-enter-the-system-usually-due-to-isolation-of-system-components))\n- Completely fix problems related to restoring backups\n- Fix app not responding (white screen) under specific situations\n\n## 4.1.7 (2020-03-10)\n\n- \"Export isolated files\" rule now participates in the calculation of \"Fix app interaction\" feature (Affected apps need to be restarted for changes to take effect)\n- Fixed an issue that modifying \"Accessible folder template\" would not take effect immediately\n- Fixed multi-user support broken due to system update\n- Add foolproof design to the process of isolating critical system apps and app groups\n\n## 4.1.6 (2020-03-06)\n\n- Ability to use built-in logcat to get boot log (no longer clear logs on start & fix UI not responding)\n- \"Export isolated files\" rules for uninstalled apps are not used in conflict checking now\n- Fix \"File monitor\" is not refreshing once the user has entered other pages\n- Fix very few records are randomly not showing in \"File monitor\"\n- Fix isolated apps rarely not starting\n\n## 4.1.5 (2020-03-04)\n\n- Completely solve the problem solved in the previous version\n\n## 4.1.4 (2020-03-03)\n\n- Fix the problem that \"Block system remount\" feature not working<sup>**〔1〕**</sup>\n\n<sub>**〔1〕** This feature should be necessary only on MIUI 11 (maybe China version only?)</sub>\n\n## 4.1.3 (2020-03-01)\n\n- Adjust the timing of starting part of the core service again (on MIUI and maybe other weird systems, too early or too late will cause problems, it's too difficult\n- Fix an issue about restoring backups\n\n## 4.1.2 (2020-02-29)\n\n- Fix random purchase information lost happened on some users introduced in v4.0.0\n- Add \"Disable notifications from Export isolated files rules\" option, because notifications don’t make sense after using \"Fix app interaction\" in enhanced mode (this option is only enabled by default for new users)\n- Fixed an issue with the \"Export isolation file\" feature when adding / updating / removing rules for an App group \n- Fixed the problem that some apps cannot be restored when restoring a backup\n- Fix a few issues related to \"Fix app interaction\"\n\n## 4.1.0 (2020-2-28)\n\n- To avoid problem, isolation for all non-regular app (uid < 10000) will be disabled on this upgrade (it's reported that isolate uid 1000 may cause problems on heavily modified system such as MIUI, OnePlus Oxygen OS, etc.)\n- Fix File monitor is breaking on last version\n- Fix possible configuration lose on last version\n\n## 4.0.0 (2020-2-28)\n\n- Change app name to \"Storage Isolation\" since \"redirect\" is very easy to make people think that it is \"redirect to SD card\" in the old days\n- Correctly support the `SharedUserId` mechanism of the Android system (almost all parts need to be changed, and most of the time has been spent here since the last update)\n- Core services continue to function after an \"abnormal restart\"\n- Fixed an issue where storage permission was displayed as allowed but denied in fact on Android 10\n- AOSP apps is no longer considered as verified in online rule\n- If someone rename \"Android\" folder to \"android\", \"Export isolated files\" continue to function (Why there is people do this)\n- Enhanced mode v22: Start some of the core services earlier, this resolves the issue where enabling isolation for apps start very early may cause the system to fail to boot (yeah, another 💩 MIUI only problem)\n- The version of Enhanced mode and Riru will never show \"unknown\"\n- If you reinstall the app that has enabled isolation, the original settings will be restored correctly (the isolation still needs to be manually turned on)\n\n## 3.2.2 (2019-12-22)\n\n- Fix a problem related to restoring the backup\n\n## 3.2.0 (2019-12-18)\n\n- Fix a problem related to isolation for the app which starts very early (yeah, another problem caused by \"changes for 💩 MIUI\")\n- UI improve for almost every part\n\n## 3.1.5 (2019-12-06)\n\n- Revert some changes in 3.1.4 since it seems to cause problems on some other devices :(\n\n## 3.1.4 (2019-12-05)\n\n- Fix a problem of startup progress\n\n## 3.1.3 (2019-11-24)\n\n- Try to avoid the problem of \"Block system remount\" may cause \"reboot\" on some devices (Note, new changes requires reboot to take effect)\n- Export isolated files (Synced folder) function now delete file with same name in target folder first, this is to avoid the problem of multiply rename/move may cause \"wrong\" file be exported\n- Add preset strings of local rules for the situations of online rules is disabled or network is unavailable\n\n## 3.1.0 (2019-11-23)\n\n- Enhanced mode: \"Fix app interaction\" can handle requests of \"Download Manager\"\n- Fix the problem that storage permission may not granted correctly on Android 10\n- Other minor bug fix and UI improve\n\n## 3.0.0 (2019-11-21)\n\n- Redesign multiple UI parts to reduce the difficulty of understanding\n- Refactor multiple UI related parts to make it more stable and smooth\n- Enhanced mode v21: Add \"Block system remount\" feature to avoid system triggered remount makes the isolation invalid (available on Android 9+)<sup>**〔1〕**</sup>\n- Enhanced mode: Bring back the feature of modifying file path in \"Fix app interaction\", but only `ACTION_VIEW` is handled<sup>**〔2〕**</sup> and it no longer use Storage Redirect app as proxy<sup>**〔3〕**</sup>\n- Redesigned online rule, making it more flexible\n\n<sub>**〔1〕** This feature should be necessary only on MIUI 11</sub>\n<br><sub>**〔2〕** Trigger deserialization of `extras` is dangerous</sub>\n<br><sub>**〔3〕** Even if we don’t do anything, the original behavior has already caused crash on Android 10, we don’t have to \"fix problem\" for \"bad apps\"</sub>\n\n## 2.1.5 (2019-10-30)\n\n- Fix some UI bugs\n\n## 2.1.4 (2019-10-29)\n\n- Improve the implementation of core\n- Fix some UI bugs\n\n## 2.1.3 (2019-10-23)\n\n- Bypassing the problem that using auto dark theme causing crash on OnePlus Android 10 (this problem is caused by OnePlus)\n\n## 2.1.1 (2019-10-23)\n\n- Fix the problem that enabled app can't start if core process starts later than it\n\n## 2.1.0 (2019-10-22)\n\n- Simplify the process of allowing access for files belonging to other apps, now all files created by other apps can be chosen from \"Folders belonging to other apps\"\n- Check and grant permissions every time when app starts, the could solve the problem caused by MIUI 11 random tampering permissions\n- Bypassing the problem of core processes being killed when using built-in su on Meizu devices\n- Temporarily remove \"modify file path\" feature in \"Fix app interaction\" because this feature can cause problems in app that use plug-in or hot fix technology (common in apps from mainland China), and currently mainstream apps should have switched to Content Provider to sharing files, removing this feature should have little effect\n- Other bug fixes and lots of UI improvements\n\n## 2.0.1 (2019-09-27)\n\n- Fix \"Shared folder\" rules not work\n\n## 2.0.0 (2019-09-27)\n\n- Check the \"Shared folder\" and \"Sync folder\" rules (the problematic rules will be deleted or disabled), and the next version will provide more detailed tips and tutorials for this issue\n- Fixed several issues with the \"Sync folder\" rule\n- Fixed separate \"Fix app interaction\" switch broken\n- Enhanced mode v20.1: Fixed an issue with the \"Fix app interaction\" feature on OnePlus Android 10 (and possibly others)\n- Lots of UI improvements\n\n## 1.9.1 (2019-09-09)\n\n- Fix the problem that \"Fix app interaction\" may not work\n- Add an option to use status bar & navigation bar\n- Fix several UI bugs\n\n## 1.9.0 (2019-09-08)\n\n- Enhanced mode v20.0: Fix the problem that redirection not work for apps installed in external storage card when using [Adoptable Storage](https://source.android.com/devices/storage/adoptable)\n- Enhanced mode v20.0: Change the implementation of \"Fix app interaction\", no longer be break by \"Xposed Taichi\", it may also solve some other problems\n- Enhanced mode v20.0: \"Fix app interaction\" can be switched individually for each app\n- Fix the problem that some configs can't be restored by backup feature\n- Allow `OP_REQUEST_INSTALL_PACKAGES` automatically on Android Q (since the change of it will trigger remount by the system)\n\n## 1.8.3 (2019-08-30)\n\n- Fix some UI bugs\n- Fix a critical problem under \"Basic mode\"\n\n## 1.8.2 (2019-08-27)\n\n- Handle special system apps (appId < 10000 or appId > 19999, appId = uid % 100000)\n- Don't fix permission for special system apps\n- Other bug fixes and UI improvements\n\n## 1.8.1 (2019-08-26)\n\n- Improve the process of selecting \"Accessible folders\"\n- Directly choose apps of \"Accessible folders template\"\n- Fix the problem that running apps with storage isolation enabled will be invalid when service start on Android Q \n- Fix high CPU usage if stay in the app for long\n- Fix other apps using API (not published yet) will crash\n- Other bug fixes and UI improvements\n\n## 1.8.0 (2019-08-17)\n\n- When choosing \"Accessible folders\", multiply templates and custom can be chosen at the same time\n- Add \"Folders analysis\", learn the size of folders in isolated storage\n- Automatically create folders in \"Accessible folders\" if not exists\n- Some UI improvements and bug fix\n\n## 1.7.5 (2019-08-06)\n\n- Fix \"Synced folder\" feature is broken\n\n## 1.7.4 (2019-08-05)\n\n- Use `FLAG_PERMISSION_SYSTEM_FIXED` to fix permission on Android Q\n- Provide a solution for Huawei devices, [see here](./guide/compatibility/huawei.html)\n- Fix \"Synced folder\" feature not trying to handle \"move files from target folder\" event\n- Improve English translation\n- Other minor changes\n\n## 1.7.2\n\n- Fix \"Code 5\"\n- Other bug fix\n\n## 1.7.0\n\n* Basic mode now works on Android Q beta 4\n* Correctly handle hide/unhide (commonly used by \"Freeze\" apps)\n* Change target SDK version to 29 (Android Q)\n\n## 1.6.12\n\n* Fix app list not refreshed after restoring backup\n* Use a more reliable method to monitor app install/uninstall\n* Notify user if no browser app available when opening help documents\n* Fix a bug related \"Fix app interaction issues\" \n* Other bug fix\n* UI improve\n\n## 1.6.9\n\n* Fix Enhanced mode not work for apps starts early than core service\n\n## 1.6.8\n\n* Fix apps not starting on new users\n* Support Android Q beta 3 (including Enhanced mode)\n* Remove the ability to choose \"Android/sandbox\" as isolated storage path since from Q beta 3 the system sandbox is only used for apps which declared support the sandbox\n\n## 1.6.7\n\n* Clear config (app info - storage - clear/manage data) feature dose clear all configs now\n* Filter duplicates or incorrect mounts in the final stage to avoid problems from user misuse\n* Fix \"Fix app interaction issues\" may incorrectly handle files in `Android/data(media, obb)/package`\n\n## 1.6.6\n\n* Fix app interaction issues (Enhanced mode): Grant content uri permission\n* UI improve\n\n## 1.6.4\n\n* Fix app interaction issues (Enhanced mode): Always convert file uri to content uri on Android Q\n* Enhanced mode: remove disable file uri expose check since it is meaningless\n* Allow choosing \"Android/sandbox\" as isolated storage path on Android Q\n* Other bug fix\n\n## 1.6.3\n\n* Enhanced mode works on Android Q\n* Enhanced mode: force disable file uri expose check for Android Q system ui\n* Improve App settings UI\n* Try fix config lost (should be extremely rare), add \"Debug info\" for users to investigate this problem\n* Fix storage permission can't be revoked if redirect is already disabled\n\n## 1.6.2\n\n* Add \"View gallery as this app\", you can learn which photos the app can access\n* Bug fix & UI improve\n\n## 1.6.0\n\n* Works on Android Q DP2 (enhanced mode not supported yet)\n* Change behavior, mount Android/media/xxx & Android/obb/xxx by default\n* Huge UI improve\n* Fix \"Fix app interaction issues\" never worked on some devices\n\n## 1.5.7\n\n* Continue fixing bugs caused by \"Fix app interaction issues\"\n* Continue renaming options\n\n## 1.5.6\n\n* Fix new storage permission method breaks on MIUI\n* Fix \"Fix app interaction issues\" feature causes app breaks on some situations (if extra contains Parcelables from non-BootClassloader)\n\n## 1.5.5\n\n* (Android 6.0-7.1) Fix \"Fix app interaction issues\" feature cause app crash or all media not shown\n* Continue renaming options, app name would even change in the future\n* Reduce extra app launching time\n  \n  On my OnePlus 3T, average extra time reduced from 0.3s to 0.16s\n  \n  * Enforce storage permission with API (do not need check everytime), save average 0.04s\n  * (only on 7.0+) Limit \"File monitor\" hook target, save average 0.1s\n  \n## 1.5.3\n\n* Enhancement module v19, please upgrade as soon as possible\n\n  * \"Fix app interaction issues\": try bypassing the problem that apps use \"Tencent app protect\" (腾讯乐固) will crash (v19)\n  * \"Fix app interaction issues\": fix some media are filtered incorrectly (app 1.5.1, v19)\n  * \"Fix app interaction issues\": fix app may crash when \"Access files from other redirected app\" rules enabled (v18.1)\n\n## 1.5.0\n\n* New Enhancement module v18\n  \n  Rewrite \"Fix file uri\" feature, upgrade to \"Fix app interaction issues\" feature \n  \n* UI change\n* Rename some options, reduce the understanding difficulty\n\n## 1.4.9\n\n* Fix \"Synced folders\" feature is broken in 1.4.8\n\n## 1.4.8\n\n* Fix regex check of \"Synced folders\" rules is not proceed when enabling the rule\n* Revoke app storage permission automatically when disabling redirect\n* Other bug fix\n\n## 1.4.7\n\n* Fix Enhancement module installation error reporting\n* Fix Google purchase issue reporting\n* Bad connection with Google Play will not freeze the whole app forever (but 5s)\n* Fix \"Fix file uri\" feature in Enhancement module may sometimes crash redirected app \n* Correctly report some type of error on start\n* Other bug fix\n\n## 1.4.6\n\n* Improve Enhancement module installation detection and provide solution\n* Improve \"Invalid license\" page\n* Bug fix\n\n## 1.4.4\n\n* Bug fix\n\n## 1.4.2\n\n* Report Enhancement module not correctly installed\n* Improve home\n\n## 1.4.1\n\n* Fix license check\n\n## 1.4.0\n\n* New home page\n* Rename/re-layout options, reduce the understanding difficulty\n\n  * \"Non-redirect folders\" -> \"Read/writable folders in real storage\"\n  * \"Link\" -> \"Synced folders\"\n\n* New Enhancement module v17, not more \"I can't open redirected apps\"\n* Fix tons of bugs\n\n## 1.3.3\n\n* Fix bug of Enhance module v16\n\n## 1.3.2\n\n* Enhance module v16, fix a problem related to passing file uri\n  (Example: can't open a received file in WeChat)\n* New native starter (for some strange devices without executables like `chmod`, `rm`)\n* Fix bugs related to link feature\n* Other minor bug fix\n\n## 1.2.2\n\n* Fix mask template for link rule editor\n* Add \"Link function only\" filter in \"Logcat\"\n* Minor bug fix\n\n## 1.2.1\n\n* Add \"Kill Media Storage on start\" option\n  (on some devices, Media Storage can use all CPU on boot, kill it can solve the problem\n  (it can be started by other apps later))\n* Add mask template for link rule editor\n* Try to detect no log\n* Minor bug fix\n\n## 1.2.0\n\n* Add \"Shared folder\" to solve the problem that files created by\n  a redirected app can't be used by another redirected app\n* Refreshed detail UI\n* Enhanced \"Redirect storage viewer\"\n* Enhanced filter for \"File monitor\"\n* Enhance module v15, fix the problem that redirect apps can't move files between specific folders\n  (Example: bilibili can't save gif)\n* Minor bug fix\n\n## 1.1.4\n\n* Enhanced \"Non-redirect folders\" template mechanism\n* Show conflicting rule info\n\n## 1.1.2\n\n* Simplified detail UI\n* Try to support other su, confirmed support MagiskSU, SuperSU, LineageOS addonsu now\n* Fix the problem that server may send wrong progress to client\n  when change \"Default redirect target\"\n* Delete redirected app config after that app uninstall\n* Improve app list performance\n* Improve chooser dialogs\n* Improve File monitor\n* Add non standard behavior check (use file monitor data)\n\n## 1.0.2\n\n* Fix UI not refreshed when add link rules online\n* Fix the problem that \"You have already own this item\" happens on some Google Play users\n\n## 1.0.0\n\n* Add \"Non-redirect folders\" template, you can create different templates\n  for different situations and apply them quickly\n* Enhance module v14, changes behavior, may avoid some special problems on\n  some devices\n* Bug fix\n\n## 1.0.0-rc9\n\n* New logcat UI\n* Fix unpaid state check\n* Migrate to AndroidX library\n\n## 1.0.0-rc8\n\n* Improve user experience\n* Minor bug fix\n\n## 1.0.0-rc7\n\n* Fix \"Launch\" button not work\n\n## 1.0.0-rc6\n\n* Improve user experience\n* Bug fix\n\n## 1.0.0-rc5\n\n* Add White / Light blue theme\n* Try to hide overlay packages\n* Fix can't open installer in file browser\n* Fix some link rules can't be added\n* Bug fix\n\n## 1.0.0-rc4\n\n* Add manually set /data/media path for some special devices\n* Bug fix\n\n## 1.0.0-rc3\n\n* Fix Android/data can be chosen as a \"Non-redirect folder\"\n* Bug fix\n\n## 1.0.0-rc1\n\n* New theme\n* New detail UI\n* Add local link rule\n* Multi-user support\n* Fix backup bug, but backup files created before 1.0.0-rc1 is unavailable\n* Try to detect real internal storage path\n\n## 0.18.2-beta\n\n* Fix bug\n\n## 0.18.0-beta\n\n* \"Non-redirect folder\" (old \"Standard folder\") is now customizable like \"Redirect target folder\"\n* Add Backup & restore\n* Works with LineageOS's addonsu, but some non-core feature may break, still recommended to use Magisk\n* Fix crash when change filter in the main list\n* Fix redirected files may not be moved when change redirect target folder in some cases\n\n## 0.17.4-beta\n\n* Fix link feature not on some (old? special?) devices\n* Try to fix owner of linked files' is 0 on older Android system (chown ourselves)\n\n## 0.17.3-beta\n\n* Fix a critical bug that if an app's redirect target is set different\n  from the default, it will not able to access files in public folders\n* Fix others bugs in 0.17.x\n\n## 0.17.1-beta\n\n* Add set redirect target folder (globally and pre-app)\n* Add app installed notification\n* Also kill by uid when force stop package (for OnePlus stock ROM)\n* Improved \"Share helper\"\n* Bug fix\n\n## 0.16.4-beta\n\n* Add file stat for Redirect storage viewer\n* Fix the problem that anyone is displayed as purchased\n* Auto clean old server files\n* Try to \"fix\" IAP problem \"You have already own this item\"\n* Link files from target to source when enabling link rules\n\n## 0.16.2-beta\n\n* Enhanced File monitor: load more & filter by path / app\n* Force grant storage permission for redirected apps\n* Try to fix bug of link function (when create and delete files in a very short time)\n* Create \".nomedia\" file in Android/data/xxx automatically\n* Add shortcut for File monitor (Android 7.1+)\n* Fix crash when open help if no browser app installed\n* Add more tips\n* Fix bugs in 0.16.1 / 0.16.2\n\n## 0.15.8-beta\n\n* Files downloaded by redirected apps can be managed in Android's Files (DocumentUI) app\n* Fix log parse (only some special ROM)\n* Add \"Show disabled apps\" filter\n* New app list style\n* In-app logcat now catches logs from more sources\n\n## 0.15.4-beta\n\n* Fix reboot when new file created in folders monitored by link function (only on 8.0)\n* Fix a bug of file monitoring function of the link function\n\n## 0.15.2-beta\n\n* Try to fix crash on boot (only some users)\n* Fix log parse (only some special ROM)\n* Auto shrink file monitor database file\n\n## 0.15.1-beta\n\n* Enhance module v12.1\n\n  Fix problem that all apps unable to access the storage (only appears on some devices), but it brings some minor problems (only happens on limited situation), check Help for detail.\n\n* Other minor changes\n\n## 0.15.0-beta\n\n* New Enhance module (check Settings and Help)\n* File monitor: monitor file access in public storage (requires \"Enhance module\")\n* Try to fix bugs in 0.14.3\n\n## 0.14.3-beta\n\n* Try to fix bugs in 0.14.1 / 0.14.2\n* Magisk module v10 (check Help & support)\n\n## 0.14.1-beta\n\n* Provide new Magisk module to solve the problem that redirected apps still create files sometimes, check Help & support for detail\n* New native daemon\n* Adapt Magisk v16.4\n* Improve UI\n* App list will be loaded correctly now even if instant app is installed (Android 8.0's bug)\n\n## 0.12.13-beta\n\n* Link rule: fix the problem that some files are skipped\n\n## 0.12.12-beta\n\n* Fix the problem that some processes are ignored on **some special ROMs**\n* Link rule: ignore file which extension ends with _tmp_ or _temp_ by default\n\n## 0.12.11-beta\n\n* Some bug fix\n\n## 0.12.7-beta\n\n* Fix the problem that some process is not redirected (from 0.12.6)\n* Link rule: handle file downloaded notification by our app\n\n## 0.12.6-beta\n\n* Should work on Android P DP1\n* Link rules ignore .tmp / .temp by default\n* Some minor changes\n\n## 0.12.5-beta\n\n* Update Magisk module (download from Help & support)\n* Some minor changes\n\n## 0.12.4-beta\n\n* New link rules UI\n* Mark outdated (not exists in online configuration) link rules\n* Try to avoid some magic\n* Add \"Share helper\"\n\n## 0.12.3-beta\n\n* Add more log for starter\n* More core files to /data/adb\n* Try to avoid strange behavior on some devices when using Magisk module\n\n## 0.12.1-beta\n* **The core feature should works perfectly on all devices**\n* Provide Magisk module for starting before all apps (see Help & support)\n\n## 0.12.0-beta\n\n* Fix major issue on some devices\n* Add tip when log may be disabled\n* Linked files will only be deleted when redirected app is running in the foreground\n\n## 0.11.2-beta\n\n> Version 0.11.2 changed some implementation details, to avoid some magic problems on users who have problems using version 0.11.0\n\n* Should work on more devices now, to the user who still have problem, the problem should not break all things\n* Storage permission (both runtime permission and appops) will be automatically grant to redirected apps (to avoid magic problem)\n\n## 0.11.0-beta\n\n> In 0.11.0 and later version, we use a completely different method of implementation. The problem that hard-coded `/sdcard` cannot be redirected is solved.\n> If you have problem using the new version, please contact us for help.\n\n* A completely different implementation, guarantee that all files will be redirected (**Read help in \"Help & support\" for more detail**)\n* Server can be restarted without rebooting (**Reboot is required if upgrade from 0.9.x**)\n* Add redirected file browser\n* Add logcat\n* Add detailed help\n* Add \"verified app\" mark which means the app will never write files in non-standard dictionaries\n* Remove \"Block writing file\" feature since it is unnecessary now\n* Fix bug about link"
  },
  {
    "path": "storage_redirect/download.md",
    "content": "# Download\n\n**Requirement:** rooted Android 6.0+ device\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.redirectstorage) (automatically select architecture)\n\n[Coolapk](https://www.coolapk.com/apk/moe.shizuku.redirectstorage) (arm64 version)\n\n[GitHub](https://github.com/RikkaApps/StorageRedirect-assets/releases) (all architectures, **Samsung users please download arm version from here**)\n\n::: warning\n**Samsung users**\n\nDue to some unknown reasons of the Samsung device kernel, **Samsung devices can only use arm version**.\n:::"
  },
  {
    "path": "storage_redirect/guide/README.md",
    "content": "# Introduction\n\nAs of the time of this writing (2023-03-06), the abuse of public storage by applications in Android is still an unresolved issue.\n\nStorage Isolation is dedicated to solving this problem with as little or no impact on application functionality as possible.\n\nTo illustrate this clearly, we have to introduce some technical concepts first.\n\n### Android's design for storage space\n\nAndroid provides two categories with a total of three locations to store their files, which are:\n\n#### data area\n\nCorresponding folders:\n\n- `/data/user/<user_id>/<package_name>`\n- `/storage/emulated/<user_id>/Android/data/<package_name>`\n\n> `<user_id>` is the user ID that relates to Android's multi-user/working profile mechanism and is not relevant to the topic of this writing.\n>\n> `<package_name>` is the unique ID of the application, which is commonly known as the \"package name\".\n\nThese two folders should be used to store the application's own data and have the following characteristics.\n\n- The application does not need to request permission to use them\n- Only accessible by the application itself\n- Will be deleted after uninstalling the app or clearing the app data\n\n> The usage of `/storage/emulated/<user_id>/Android/data/<package_name>` and `/data/user/<user_id>/<package_name>` are same. It exists for some historical reasons: in Android 4.x and earlier, the storage space that came with the device was usually very small, and external SD cards was used to expand the storage space, which was then also used to store the app's own data.\n\n#### Internal storage\n\nCorresponding folders:\n\n- `/storage/emulated/<user_id>`\n\nThis place should store files that are useful to users, such as pictures saved by users in the application. Android system provides `DCIM`, `Download`, `Pictures` and other public folders for storing photos, downloaded files, etc. in different categories. This place can also be called `Share storage`, `Public storage`, etc.\n\nThis place have the following characteristics.\n\n- Storage permissions are required to read\n- Storage permissions are required to write<sup>**〔1〕**</sup>\n- Applications with storage permissions granted can read all the files, including those written by other applications or the user\n- The files written by the app will not be deleted after uninstalling the app or clearing the app data\n\n<sub>**〔1〕** There are changes after Android 11, see below</sub>\n\n### The way the application accessing the files\n\nIn addition to the most basic direct access through the file path, Android also provides several other ways.\n\n* Media store\n\n  Media store is a system application that has an internal database containing information about all files in the internal storage. The most common use case is to query all image files from Media store. Reading and writing files can also be done through the media store.\n\n* Storage Access Framework, SAF\n\n  SAF is a feature that has been added since Android 4.4. With SAF, users can open files, save files, etc. from a unified UI provided by the system. The application can also become a provider by itself, and other applications that use SAF can use it.\n\n  The benefits of SAF are that the application can only use files selected by the user, a unified UI, the application does not need to request permissions, and so on.\n  \n  However, most applications prefer to request storage permissions and implement the required functionality themselves.\n\n### What is the problem of application abuse of storage space\n\nThe abuse of storage space is the abuse of \"internal storage space\".\nSome applications or some SDKs will want their data files not to be deleted after uninstallation, so they will choose \"internal storage\" to write their data files\n\nIf apps have the ability to \"send pictures\", \"save files\", etc., users often have to grant storage permissions to the app. Then they can write a bunch of weird folders in the \"internal storage (see below). Over time, the user's storage space will become chaotic.\n\n::: details Example\n\nMany applications that abuse storage space create a bunch of weird folders, even named \"SystemConfig\" to make users think they are system files.\n\n<img :src=\"$withBase('/images/chaos_storage.png')\" alt=\"Example\">\n:::\n\n#### Scoped storage added by Android 11\n\nMany people think that Scoped storage can this problem, but this is not the case.\n\nThe behavior of applications subject to Scoped storage when using the public storage changes as follows.\n\n- Only files of the corresponding type can be written in the public folder (but the system will only check if the file name matches the rules)\n- Write files in public folders without any permissions (this is more lenient than before!)\n\nIn addition, Scoped storage only affects apps that target Android 11 or above (i.e. Target API ≥ 31). Apps that are not on Google Play or older apps that have stopped being updated are not restricted.\n\n### Solving the problem\n\nTo solve this problem above, we have created this application - Storage Isolation.\n\nThe user can enable isolation for a specific app. The \"internal storage\" used by the app will actually become a folder in `/storage/emulated/<user_id>/Android/data/<package_name>`. Therefore, the real \"internal storage\" will not be contaminated and the files created by it will be deleted after uninstallation.\n\nWe provide several mechanisms to ensure that the isolated application works properly when it needs to use the files in the Internal Storage. Please read the subsequent documentation."
  },
  {
    "path": "storage_redirect/guide/advanced/shared_user_id.md",
    "content": "# App group\n\nThe Shared User ID mechanism of the Android system allows multiple apps to share the same Linux user ID and Android permissions, access files each other, and even run in the same process. These apps need to have the same signature and Shared User ID cannot be changed after installation. To simplify the understanding, we call the Shared User ID mechanism as App group in Storage Isolation.\n\nThis means:\n\n* Some apps without storage permissions can use storage space\n* Multiple apps can run in the same process\n\nIsolation works at the process level. In versions prior to v4.0.0, only the package name was used, which obviously caused problems.\n\n### Example\n\nMedia Store, Download Manager, Download Manager UI, and MTP host have the same Shared User ID `android.media`. Media Store and Download Manager have the same process `android:process=\"android.process.media\"`. So the Media Store and Download Manager run in the same process.\n\nIn MIUI (and maybe other heavily modified systems), Download Manager abuses storage, so users will choose to enable isolation for it and only allow it to access `Download` folder. However, because Media Store runs the same process, Media Store can only access `Download`. This will cause the users' album not updating.\n\nIn addition, the Shared User ID mechanism makes app possible to use storage without storage permissions. Also for MIUI (and maybe other heavily modified systems), users will not have the opportunity to enable isolation for such apps, as they will not be shown in older versions.\n\nSo after v4.0.0, letting apps with the same Shared User ID use the same settings can solve this problem.\n\n### Behavior\n\nSuppose there are two apps `com.example` `com.example2`, and their Shared User ID is `example`.\n\n* They use the same settings (internally they are considered as one app)\n* The isolation storage location is located in `Android/data/shared-example`\n* They can access app-specific folders each other"
  },
  {
    "path": "storage_redirect/guide/advanced/technical_details_export_isolated_files.md",
    "content": "# Technical details (Export isolated files)\n\nSuppose an app `com.example` saves images to `images` folder. Created a rule for source folder `images` and target folder `Pictures/Example`.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard      <---- Isolated storage for com.example\n│       └───images  <---- Location of images (source folder)\n│           ├───1.jpg\n│           └───...\n└───Pictures\n    └───Example     <---- Exported location (target folder)\n        ├───1.jpg\n        └───...\n```\n\nAfter creating the rule, the `Android/data/com.example/sdcard/images` folder will be monitored with [`inotify`](http://man7.org/linux/man-pages/man7/inotify.7.html), and by the rule, the files inside will be \"synced\" to `Pictures/Example` with [`link` (hard link)](http://man7.org/linux/man-pages/man2/link.2.html).\n\nBecause hard link is used, only one of storage space is occupied. Other apps or systems may report usage incorrectly because they don't handle this situation properly.\n\nThe behavior of the rule:\n* Create files in source folder / Move files to source folder: link to target folder\n* Delete / move outside files in source folder: If the app is foreground, delete the files in the target folder; if it is not foreground, do nothing (this is to prevent operations from user / system / third-party apps cause file loss)\n* Create files in target folder / Move files to target folder: link to source folder at next core service startup\n* Delete / move outside files in target folder: delete files in source folder"
  },
  {
    "path": "storage_redirect/guide/compatibility/README.md",
    "content": "# Overview\n\n* [Samsung](./samsung.md)\n* [Meizu](./meizu.md)\n* [Xiaomi (MIUI)](./miui.md)\n* Other problems\n\n  * log is disabled\n\n    Check if log is enabled in \"Developer Settings\". In addition, according to user feedback, log disabled by default on Huawei EMUI. If you are using EMUI, please search how to enable log on EMUI.\n\n    Or the simplest way, using [Enhanced mode](./../enhanced_mode/).\n"
  },
  {
    "path": "storage_redirect/guide/compatibility/meizu.md",
    "content": "# Meizu\n\nIf you can use Magisk, you won't run into problems.\n\nIf you can't use Magisk, DO NOT enable isolation for the \"Settings\" app of system (or the [App group](./../advanced/shared_user_id.html) it belongs to)."
  },
  {
    "path": "storage_redirect/guide/compatibility/miui.md",
    "content": "# Xiaomi (MIUI)\n\nMIUI has a series of restrictions which **enabled by default**. However, these restrictions are too ridiculous, the normal functions of apps are always broken by them. \n\nWhat's even more irritating is that these restrictions are controlled by MIUI's online rules and will not be enabled for apps like WeChat that are popular in mainland China.\n\n## \"Display pop-up window while in the background\" permission is denied by default\n\n\"Display pop-up window while in the background\" is a permission added by MIUI, and it's **denied by default**.\n\nIt's too ridiculous since denying this permission will **break the normal behavior of apps**. It is strongly recommended to allow this permission for all well-designed apps.\n\n### Features affected\n\n1. Tap the notification of \"Export isolated file\" rule, the file cannot be opened\n2. \"Error during interaction with Play Store\" when purchasing from Google Play\n\n### Solution\n\n1. Enter \"App Info\" of \"Storage Isolation\"\n2. Tap \"Other permissions\" (for mainland China version of MIUI is \"Permission\" or \"Permission management\")\n3. Change \"Show interface in background\" to \"Allow\"\n\nFor files that cannot be opened, you may also need to allow \"Display pop-up window while in the background\" for the app responsible for opening the file.\n\nFor Google Play purchase issues, you also need to allow \"Display pop-up window while in the background\" for Google Play.\n\n## Battery saver from MIUI is enabled by default\n\nFor well-designed apps, using MIUI's power saving features **will not save more power**, instead some features may be broken.\n\n### Features affected\n\nUncertain.\n\n### Solution\n\n1. Enter \"App Info\" of \"Storage Isolation\"\n2. Click \"Battery saver\"\n3. Select \"No restrictions\""
  },
  {
    "path": "storage_redirect/guide/compatibility/samsung.md",
    "content": "# Samsung\n\nFor unknown reasons, on some Samsung devices, execute a 64-bit executable in root user will always get a `Permission denied` when using `exec` functions.\n\nThe solution is simple. Install [arm version](./../../download.html) after uninstalling."
  },
  {
    "path": "storage_redirect/guide/contribute.md",
    "content": "# Contribute online rules\n\nCurrently, you need to manually create issues on GitHub. Please follow the steps below.\n\n1. Create a [GitHub](https://github.com/) account if you don't have\n2. [Create new issue](https://github.com/RikkaApps/StorageRedirect-assets/issues/new?template=new_rule_json_en.md)\n3. Follow the instructions in the issue"
  },
  {
    "path": "storage_redirect/guide/enhanced_mode/README.md",
    "content": "# Why Enhanced mode is necessary?\n\n-----------------------\n\nEnhanced mode provides the following features:\n\n1. No longer relying on `logcat` to detect app process creation\n   - Avoid the problem that the app will not be isolated for a short period of time due to the possible delay of the log\n   - Avoid the problem that the log is disable (e.g., Huawei EMUI disable log on boot)\n2. Start on boot\n   - Avoid the problem that custom systems block start on boot (including but not limited to MIUI)\n3. Block system remount\n   - Avoid remount triggered by the behavior of custom systems making the isolation invalid (e.g., MIUI 11)\n4. Record file access behavior for apps\n4. Modify the behavior of MediaProvider and DownloadManger to prevent apps to read/write unaccessiable folders through them\n\n## Performance impact\n\n\"Enhanced mode\" only has a performance impact that can be ignored."
  },
  {
    "path": "storage_redirect/guide/enhanced_mode/install.md",
    "content": "# Install\n\nThe boost module requires your device to have Magisk installed first. You can learn more about Magisk from [GitHub](https://github.com/topjohnwu/Magisk).\n\n:::tip Tip\nAs of Magisk v24 (released on 2022-01-26), the online repository is removed. You can only install in Magisk directly after downloading the zip.\n:::\n\n## Zygisk\n\nYou can use the Zygisk version of the enhancement module (requires Storage Isolation v7.0.0) after enabling Zygisk.\n\n* [Module](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets) (choose Zygisk version)\n\n### About Zygisk\n\nZygisk is a feature added in Magisk v24. It is similar to Riru in terms of end purpose, but differs in details and implementation.\n\nZygisk has a DenyList function. After enabling Enforce DenyList option, Zygisk will not load Zygisk modules for the apps in the list. For Storage Isolation, apps in the list cannot be isolated. Note that the **DenyList is not a hide feature, it can't even hide the presence of Zygisk itself**.\n\n**The DenyList is an \"out of reality\" feature** because people obviously want to use modules while maintaining hidden. Hidden modules are also required to not enable Enforce DenyList option, otherwise hidden modules will not work because they will not be loaded.\n\nIn short, use the dedicated hiding module Shamiko to hide and never enable Enforce DenyList option.\n\n### About Shamiko\n\nShamiko is a hidden module developed by others. It can hide Magisk SU, Zygisk itself and Zygisk modules.\n\nShamiko borrowed Magisk's DenyList. That is to say, Magisk's DenyList is Shamiko's exclusion list, but in order for Shamiko to take effect you cannot turn on Magisk's Enforce DenyList option. It's a little confusing, but that's it.\n\nDownload Shamiko at [here](https://lsposed.github.io/) after 2022-02-02.\n\n## Riru\n\nIf you're using an older version of Magisk or don't use Zygisk, you'll also need to install Riru. Please download Riru and Riru version booster and install it in Magisk.\n\n* [Riru](https://github.com/RikkaApps/Riru/releases)\n* [Module](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets) (select Riru version)"
  },
  {
    "path": "storage_redirect/guide/faq/cant_find_app.md",
    "content": "# Can't find some apps\n\nOnly apps which request read <b>and</b> write storage permission will be shown (i.e., apps request only read storage permission or no storage permission will not be shown).\n\n## Apps using root/adb\n\nApps using root or adb can access storage directly as root or adb without limited by their permissions.\n\n> Apps that use adb here do not include apps that require adb to grant permissions (`pm grant`) or similar operations.\n\n## Apps using Xposed \n\nApps using Xposed can use storage through the apps they inject, i.e., the actual access to the storage space is the app they injected instead of the Xposed module app itself."
  },
  {
    "path": "storage_redirect/guide/faq/how_to_document.md",
    "content": "# How to use the Document (Files) app\n\nThe Document app is part of the Android system. The advantage is that users can use it to directly access files from a variety of sources (any application that implements DocumentProvider, such as Google Drive).\nThe downside is that Document app can be a bit difficult to use. This help will teach you how to use the file app.\n\nFirst, if you are using Document app for the first time, the internal storage of device is displayed by default.\nYou need to select \"Show internal storage\" from the three-point menu at the upper right corner to show internal storage.\n\nNext, you need to know that you can switch the current location by swiping right or clicking the three-line icon at upper left corner. If you use it for the first time, the default location may be \"Recent\". You can't create files at this location. You need to select the location you want to save.\n\n## Document app not found?\n\n> The package name of Document app is `com.android.documentui`\n\n### Using a highly customized system\n\nOn some highly customized systems (such as MIUI), Document app may be disabled or even deleted.\nYou need to find out how to solve the problem by Google it.\n\n### Disabled\n\nGo to System Settings - Applications, find Document (Files) app and enable it.\n\n### Deleted\n\nDocument app is part of the Android system.\nIf you find that the system you are using does delete the Document app, **we strongly recommend you switch to another system** because it is ridiculous to delete an important system component."
  },
  {
    "path": "storage_redirect/guide/faq/how_to_report_problems.md",
    "content": "# Report problems\n\nThis document will teach you how to report problems.\n\n> For problems that are limited to a specific app (such as unable to find pictures in the app), there is a high probability that your settings is incorrect. Please try to read other documents to learn how to set correctly.\n\n1. Make sure you are using recent versions of app\n2. Describe app version (e.g., v4.1.6.r2361)\n3. Describe your problem clearly\n4. Attach the log of the problem (if possible, indicate the approximate time when the problem occurred)\n5. Send to [support@rikka.app](mailto://support@rikka.app)\n\nIf the returns do not meet the requirements, there is a high chance that you will not receive replies.\n\n### How to grab the log\n\nYou can use the in-app logcat (the upper right corner of the home page - Logcat) to grab the log.\n\nNote that to capture meaningful logs, **you need to reproduce the problem after starting the log**.\n\n### Unable enter the system\n\nIf you cannot enter the system, you need to grab the log through adb (requires to connect to a computer). You need to search for how to use adb by yourself.\n\nConnect USB during the boot process, and execute `adb logcat > 1.txt` immediately after adb is connect."
  },
  {
    "path": "storage_redirect/guide/tutorial.md",
    "content": "# Tutorial\n\n## What happens when isolation is enabled?\n\nAssuming there is an application called ExampleApp (the package name is `com.example`). It uses an SDK that abuses storage (assuming it will create `bad_sdk` folder). Then after granting ExampleApp storage permission, your storage space will look like this.\n\n```\n/storage/emulated/0\n├───Android\n├───bad_sdk\n├───DCIM\n├───Download\n├───Pictures\n└───...\n```\n\nNow that we enable isolation for ExampleApp, the storage to it becomes a folder in its data folder. We call this folder \"isolated storage\".\n\nExampleApp will only able to use the files in this folder, and the folders created by it will also be saved in this folder.\n\n```\n/storage/emulated/0\n├───Android/data/com.example  <---- ExampleApp's data folder\n│   └───sdcard                <---- Isolated storage\n│       └───bad_sdk\n└...\n```\n\nIn addition, because of the data folder, we can also take these benefits:\n\n* These files will be deleted when uninstalling or clearing data\n* In system's app info, these files will also be counted as storage usage\n\n## Knowledge for new users\n\n::: details <b>Recommended way to organize files</b>\n\nFor user files such as photos, pictures, and downloaded files, the Android system providers a series of standard folders.\n\n* `Alarms`\n* `Pictures`\n* `DCIM` (for photos taken by camera)\n* `Documents`\n* `Download`\n* `Movies`\n* `Music`\n* `Notifications`\n* `Ringtones`\n\nTaking the most common `Pictures` as an example, it is common for each app to create its own folder in it. For example, Twitter saves pictures to `Pictures/Twitter`.\n\nOur recommendation is to organize the files saved by each app in the above way.\n:::\n\n::: details <b>Clean/Move existing files</b>\n\nSince the files in `/storage/emulated` do not have owner, we cannot automatically help you move or delete existing files.\n\n* User files, such as pictures\n\n  Organize as the recommendation above.\n\n* Other\n\n  For most apps, deleting previous files will not cause problems. But just in case, we recommend that you follow the steps below.\n\n  1. Create a temporary folder and move them into it.\n  2. Run all isolated app.\n  3. If there are some apps not work properly because of can't find previous files, you can learn folders were created by which app by using \"View isolated storage\" option. Then you can move those folders.\n  4. After all apps are working properly, delete the temporary folder.\n:::\n\n::: details <b>Forget about \"Cleaning app\"</b>\n\nSome \"Cleaning app\" have the function of cleaning files created by specific apps (those files are not in data folder, they will not be deleted after uninstallation). This function cannot be used because file location changes after isolation.\n\nHowever, after isolation, files created by the app are stored in the isolated storage (located in its data folder). They will be deleted after uninstallation. In addition, you can set the location of the isolated storage to cache folder. Cache folder is automatically cleaned up by Android system.\n\nForget about \"Cleaning app\", they are no longer meaningful. And they should not exist from the first day.\n:::\n\n::: details <b> \"Backup app\" are not affected (you can even backup more files)</b>\n\n\"Backup app\" could only backup files inside apps' data folders.\n\nAfter isolation, the files created by the app are saved its isolated storage (located in its data folder), so these files could also be backed up. Note, you may need to enable an option like \"Backup external data\" in your \"Backup app\".\n:::\n\n::: details <b>Use Enhanced mode</b>\n\nEnhanced mode is an very important part, [many problems](./enhanced_mode/) can only be solved in the case of using Enhanced mode.\n\nWe recommend that you to try Enhanced mode when you are sure everything is OK (you can see how to use Enhanced mode in the app).\n:::\n\n## Solutions for apps not working properly\n\n### App needs to access specific files\n\nNow ExampleApp has the function of sending pictures. But because of the isolation, you cannot find your picture in ExampleApp.\n\nTo solve this problem, we only need to focus on the \"Shared folders\" section of the \"Accessible folders\" option. Assuming we selected folder `DCIM` and` Pictures`, then ExampleApp can access the files in these two folders.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard        <---- Isolated storage\n│       ├───bad_sdk\n│       ├───DCIM      <---- Real DCIM\n│       └───Pictures  <---- Real Pictures\n└...\n```\n\nFor other cases, you only need to select the corresponding folder.\n\nNote, app can not only read but also write these folders.\n\n#### DO NOT abuse!\n\nWe only recommend that the necessary folders be made accessible. If you make all folders accessible, isolation will be meaningless.\n\n### Can't find files saved by the app\n\nNow ExampleApp has the function of downloading pictures, and you use it to download `1.png`. Because it is isolated, `1.png` is saved to isolated storage, so you cannot see it in the album app.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard         <---- Isolated storage\n│       ├───bad_sdk\n│       ├───DCIM\n│       ├───images\n│       │   └───1.png\n│       └───Pictures\n└...\n```\n\nTo solve this problem, we need to create an \"Export isolated files\" rule.\n\n```\nSource: images\nTarget: Pictures/ExampleApp\nAdd to Media Store: Yes\n```\n\nAfter creating this rules, you will be able to see `1.png` in album apps and `Pictures/ExampleApp`.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard               <---- Isolated storage\n│       ├───images\n│       │   └───1.png\n│       └───...\n├───Pictures\n│   └───ExampleApp\n│       └───1.png\n└...\n```\n\nNote that since the hard link is used, although the same file exists in two places, **they only occupy one storage space**. For technical details on \"Export isolated files\", you can read it [here](./advanced/technical_details_export_isolated_files.md).\n\n#### Use online rules\n\nIf there are already required rules in the online rule, you only need to add them directly. You only need to write your own rules when there are no rules or when there are errors of online rule. You can also submit your rules to the online rule library (via the \"upload button\").\n\n#### DO NOT abuse!\n\nThe purpose of export is to export **user files (save file operations initiated by the user, such as saving pictures, downloading files, etc.)**.\n\nIf the app saves user files to a private folder (e.g., `Android/data/<package>/files/example`), this place is not belong to isolated storage which is not applicable for export function.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   ├───files                <---- NOT belong to isolated storage\n│   └───sdcard               <---- Isolated storage\n└...\n```\n\nIf you find the save **user files** to private folders, you should ask the app developer to make changes.\n\n::: details Why you should ask the app developer to make changes?\n\nIn Android 11, `Android` folder is the real private folder. Even with storage permissions, apps can only access the part that belongs to it.\n\n```\n/storage/emulated/0\n├───Android\n│   ├───data\n│   │   └───com.example     <---- Belongs to com.example\n│   ├───media\n│   │   └───com.example     <---- Belongs to com.example\n│   └───obb\n│       └───com.example     <---- Belongs to com.example\n└...\n```\n\nStoring user files in private folders means except the app itself, **any other app, including file managers, cannot see the files**. This is obviously wrong. In addition, the files here will be deleted when the data is uninstalled or cleared. It is obviously inappropriate to save user files here.\n\nNote that for the scenario like \"receiving files in a chat app\", it is reasonable to store the files in a private folder first. Therefore, when giving feedback to the app developer, ask them to add a \"Save to Download\" function (moving the files in the private folder to the `Download` folder) instead of directly changing the location of the files.\n:::\n\n::: details Another \"solution\"\n\n<https://github.com/RikkaApps/SaveCopy>\n:::\n\n### Problems when cooperating with other apps\n\n#### Use other apps to view files (standard way, ACTION_VIEW)\n\nExampleApp now has the ability to use other apps to open pictures. Unfortunately, ExampleApp directly passes the file path to other apps (this approach should be abandoned a few years ago!), You will find that other apps shows \"file not found\".\n\nExampleApp does not know that it is isolated, it sees storage space like this.\n\n```\n/storage/emulated/0    <---- ExampleApp's view\n├───bad_sdk\n├───DCIM\n├───images\n│   └───1.png\n└───Pictures\n```\n\nTherefore, the situation is like this.\n\n> ExampleApp: Here you are, `example_app/1.png`.\n>\n> Image viewer: Let's try opening this file... It seems not exists!\n\nWe all know the file is located at `/storage/emulated/0/Android/data/com.example/sdcard/images/1.png`.\n\n::: tip No need to support this situation\n\nIn Android 11, `Android` folder is the real private folder, this approach does not work. Apps doing this must make changes. Therefore, from v4.4.0, support for this situation has been removed.\n:::\n\n#### Pass file path to other isolated apps with non-standard ways\n\nExampleApp now adds the ability to share pictures to ExampleSocial (ExampleSocial is also an isolated app). Unfortunately, ExampleSocial requires the use of its SDK (this method should also be abandoned!), which means that the file path is passed directly, and we can’t change the file path through the \"Fix app interaction issued\" function.\n\nAssuming ExampleSocial's SDK works like this: save the picture to the `tmp` folder and pass the file path to ExampleSocial.\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard    <---- ExampleApp's isolated storage\n│       └───tmp/shared_image\n└───Android/data/com.social.example\n│   └───sdcard    <---- ExampleSocial isolated storage\n│       └───...\n└...\n```\n\nTo ExampleSocial, the `tmp` folder does not exist, so sharing will fail.\n\nTo solve this problem, we need to create a \"Accessible folder\"-\"Other application folder\" rule.\n\n```\nSource app: ExampleApp\nTarget app: ExampleSocial\nFolders: tmp\n```\n\nSo that ExampleSocial can access the `tmp` folder from ExampleApp.\n\n#### How to create my own rule?\n\nYou need to pick up your \"weapon\", \"File monitor\". File monitor is a function from \"Enhanced mode\".\n\nContinuing the above example, after the sharing of ExampleApp to ExampleSocial fails, in File monitor, you will able to find records of `tmp` folder from both ExampleApp and ExampleSocial. This shows that you need to create the rule of accessing the `tmp` folder.\n\n#### Use online rules\n\nIf there are already required rules in the online rule, you only need to add them directly. You only need to write your own rules when there are no rules or when there are errors of online rule. You can also submit your rules to the online rule library (via the \"upload button\").\n\n#### Bonus\n\n::: details <b>Involving Xposed modules</b>\n\nFirst of all, you need to know that the Xposed module runs not only as the module apps itself, but also in other applications.\n\nFor example, a module named ExampleXposedModule has the function of modifying ExampleApp, it will run in ExampleApp. If ExampleXposedModule saves settings by creating files, ExampleApp also needs to read the saved file. This is the same situation as ExampleApp sharing to ExampleSocial.\n\nWhat you need to do is to use \"file monitoring\" to monitor which files are used and create corresponding rules.\n\n**However, the most correct approach should be to ask Xposed module developers to make changes!** (Ask module developers to use `ContentProvider` to share the configuration, or directly save the configuration in the data folder of the target app.)\n:::"
  },
  {
    "path": "storage_redirect/zh-hans/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 下载\nactionLink: /zh-hans/download.html\nsecondaryActionText: 了解更多\nsecondaryActionLink: /zh-hans/guide/\nfeatures:\n- title: 再无滥用\n  details: 为指定的应用启用隔离，它们将只能访问用户指定的文件夹。\n- title: 带回整洁的存储空间\n  details: 坏应用不再可以建立一堆文件夹；根据用户设定规则将用有用的文件、媒体等存至规范的文件夹。\n- title: 监视文件操作\n  details: 监视应用的文件操作，了解其使用了哪些文件。\nfooter: Copyright © 2023 RikkaApps\n---"
  },
  {
    "path": "storage_redirect/zh-hans/changelog.md",
    "content": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- 修复了在 Android 10 以上，没有写存储权限的应用没有显示“导出被隔离的文件 & 重定向系统提供程序”选项的问题\n  \n  在 Android 10 以上，Android 系统允许符合条件的应用（**即使它没有请求任何权限**）写入标准文件夹（符合条件的应用是指目标 API 是 30 或以上，或者目标 API 是 29 且适配了分区存储的应用）。此选项对此类应用是有意义的。\n\n## 8.4.2 (2023-03-22)\n\n- 修复自从 8.4.0 版本起，如果“暗色主题”没有被设为“跟随系统”时应用无法使用的问题\n\n## 8.4.1 (2023-03-17)\n\n- 修复上个版本中在未使用增强模式的情况下进入应用列表时应用会崩溃的问题\n\n## 8.4.0 (2023-03-12)\n\n- 修复首次启动核心服务时会强行停止有导出规则的应用（不论规则是否启用）的问题\n- 【仅限 Android 10 及之前的版本】文件监视功能不再强制要求安装 Shamiko（但请注意，隐藏解决方案仍是必要的，因此文件监视的开关在更新后会被关闭）\n- 修复只请求了 Android 13 添加的权限的应用被判定为未请求权限的问题（上个版本并未正确修复）\n- 针对中日韩语言用户，如果系统没有提供 Medium（500）字重的字体，则会使用模拟实现\n\n## 8.3.0 (2023-01-03)\n\n- 修复了 Android 11 以上未请求权限的应用被跳过不处理的问题（在 Android 11 以上，无任何权限的应用也可以在标准文件夹中写入文件和文件夹）\n- 修复只请求了 Android 13 添加的权限的应用被判定为未请求权限的问题\n\n## 8.2.2 (2022-12-05)\n\n- 在请求在线规则前需要用户同意\n\n## 8.2.1 (2022-11-22)\n\n- 更好的 Android 13 支持\n\n## 8.1.0 (2022-10-15)\n\n- 保证带有 `Shared user ID` 的应用会使用固定的隔离存储空间\n- 修复在使用 Zygisk 版本的增强模块时进行了一些不必要的检查的问题\n- 提前修复一个会导致受限模式在下一个 Android 版本无法使用的问题\n\n## 8.0.0 (2022-08-21)\n\n- 全新的文件监视实现\n- 在 Android 10 及更高版本停用实际不需要的“修复 rename”\n- 修复重新安装卸载但保留数据的应用不显示的问题\n\n新旧文件监视的区别：\n\n旧：\n- 需要进入每个进程（可能会被检测，尤其是 Zygisk 版本）\n- 不能记录直接 syscall 的和延后载入的原生库进行的操作\n\n新：\n- 无需进入所有进程\n- 可以记录原先不能记录的操作，但是不能记录被隔离的应用进行的操作\n- 需要 Android 11 及以上版本（如果设备运行 Android 10 或更旧版本则仍会使用旧版本）\n\n## 7.5.3 (2022-06-14)\n\n- 修复 v7.5.2 在 Android 10 及以下坏掉\n\n## 7.5.2 (2022-06-14)\n\n- 修复“处理系统提供程序”导致某些应用无法访问已设置为可访问的文件的问题\n\n## 7.5.1 (2022-06-09)\n\n- 修复在 Android 13 Beta 3 上不工作\n\n## 7.5.0 (2022-05-20)\n\n- 增强模块 v27：在没有 sdcardfs 的设备上恢复“访问其他应用的文件夹”功能\n- 一些 UI 调整\n\n## 7.3.4 (2022-05-06)\n\n- 重做备份和恢复功能（旧的备份仍然支持，但是强烈推荐使用新版本应用程序创建新的备份）\n- 试修复损坏的数据库文件导致文件监视功能坏掉\n- 切换到 Material Design 3（Material You）\n\n## 7.1.0 (2022-02-22)\n\n- 支持 Android 13 DP1（但是，根据经验，DP1 是非常早期的版本，应用程序很可能会因为 DP2 的改动再次无法工作）\n- 增强模式 26.1.0：修复文件监视功能导致下载管理器在部分 OnePlus（OPPO）设备上坏掉的问题\n\n## 7.0.0 (2022-01-29)\n\n- 增强模式支持 Zygisk\n- 修复不能列出仅在非主用户中安装的应用的问题\n## 6.4.0 (2021-12-13)\n\n- 修复在 Android 11 以上，为带有 `Shared user ID` 的应用建立导出规则时，无法选择来源文件夹的问题（没有显示任何文件夹）\n- 一些 UI 调整\n\n## 6.3.0 (2021-11-14)\n\n- 更正有关 Android 11 上应用无需权限即可写入文件到标准文件夹的说明\n- 一些 UI 问题修复\n- 提升目标 SDK 版本到 31\n\n## 6.2.0 (2021-10-14)\n\n- 显著提高文件监视的性能，特别是对于有大量记录的用户\n- 修复当给文件监视设置了过滤时常常无法展示所有记录的问题\n- 修复文件监视可能不能正确展示来自“媒体存储”的记录的问题\n- 更正有关 Android 11 上目标 API 为 30 以上的应用无需权限即可写入文件到标准文件夹的说明\n\n## 6.1.10 (2021-09-16)\n\n- 在 Android 11 以上，允许为媒体存储设备等应用将 `Android` 文件夹中的文件夹设为可访问文件夹\n\n## 6.1.9 (2021-09-03)\n\n- 修复在没有 `sdcardfs` 的设备上，应用可能无法访问被“导出被隔离的文件”规则所使用的文件夹的问题\n- 修复一个 UI 问题\n\n## 6.1.8 (2021-08-29)\n\n- 当文件监视的数据库损坏时重新建立\n- 修复一个会导致核心服务崩溃的内部问题\n\n## 6.1.5 (2021-08-12)\n\n- 正确处理系统服务重新启动\n\n## 6.1.4 (2021-07-14)\n\n- 修复自从 6.1.0 版本起可能不能正确地隔离带有 `Shared user ID` 的应用的问题\n- 修复不能在不同的用户添加相同的“允许访问来自其他应用的文件夹”规则的问题\n- 修复可访问文件夹选择器不能显示不存在但已选择的文件夹的问题\n\n## 6.1.0 (2021-06-30)\n\n- 允许隔离只有读存储权限的应用\n- 在 Android 10+，在增强模式下，允许隔离无存储权限的应用\n  \n  没有存储权限的应用可以通过媒体存储将媒体（图片、视频、音乐）文件写入标准文件夹。有些应用通过生成假媒体文件来持久化其数据。\n\n- 修复增强模块有时显示为没有安装的问题\n- 修复在 x86 设备开启就崩溃\n- 从应用列表隐藏部分应用（无组件的应用、无代码的应用、overlay 应用，此类应用无法运行，隔离它们没有意义）\n\n## 6.0.2 (2021-06-27)\n\n- 增强模块 v25：\n  - 应用不再可以通过媒体存储设备使用非可访问文件夹（旧版本无法处理 Android 10 开始的新方法）\n  - 应用使用媒体存储设备的事件可被文件监视记录\n  - 从零开始重做与媒体存储设备有关的部分，相较以前有更好的性能及兼容性\n- 改进文件监视 UI\n- 修复从 Android 12 Beta 1 开始，相册预览会让核心服务崩溃\n- 由于模块 v25 的巨大变化，旧版本的增强模块不再支持\n- 移除一些从超级旧的版本迁移设置的代码\n- 修复在 x86 设备开启就崩溃\n\n## 5.4.5 (2021-05-21)\n\n- 受限模式（不安装增强模块）在 Android 12 Beta 1 上工作\n- 为文件监视添加“排除私有文件”选项\n\n## 5.4.3 (2021-05-06)\n\n- 修了可访问文件夹模板需要较长时间才能加载的问题\n\n## 5.4.1 (2021-05-04)\n\n- 阻止 💩 MIUI 的“强制深色模式”弄坏自己的深色主题<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI 有自己的“强制深色主题”，但是似乎即使应用正确地提供了深色主题，它也会继续起作用，从而把颜色改乱。</sub>\n\n## 5.4.0 (2021-05-03)\n\n- 尝试解决可能存在的不能隔离 Android 11 及以上版本的媒体存储设备的问题（在 MIUI 上，隔离它可能是必要的）\n- 增加了多个针对 Android 11 及以上版本系统的防呆设定\n- 记录从始至终执行隔离的次数\n\n## 5.3.5 (2021-04-28)\n\n- 尝试修复一个可能导致核心服务崩溃的问题\n- 从应用列表隐藏部分应用（无组件的应用、无代码的应用、overlay 应用，此类应用无法运行，隔离它们没有意义）\n\n## 5.3.4 (2021-04-27)\n\n- 修复一个只在极少的设备上出现的“修复应用间交互”功能导致被隔离的应用卡死的问题\n\n## 5.3.1 (2021-03-27)\n\n- 采用[自己编译的 libcxx](https://github.com/RikkaW/libcxx-prefab)来减少文件大小（减少了约 300KB）\n- 增强模块升级到 Riru 25\n- 适应一个 Android 12 的改变\n- 当增强模式没有正常工作时给予提示\n- 处理了一些 Android 11 及以上用户主动关闭了 fuse 后的问题\n\n## 5.2.0 (2021-01-27)\n\n- 修了在 Android 11 上无法修改非主用户的应用的设定的问题\n\n## 5.1.0 (2021-01-19)\n\n- 支持通过 Sui（https://github.com/RikkaApps/Sui）启动（当然由于这个应用复杂度过高，真的就只是启动而已）\n- 文件监视现在显示非主用户的记录\n\n## 5.0.2 (2020-12-20)\n\n- 修了一个可能导致有 `sharedUserId` 的应用（应用内称为“程序组”）无法被隔离的问题\n- 当“阻止系统重新挂载”可用时不再自动允许 `OP_REQUEST_INSTALL_PACKAGES`（以前这么做的原因是 `OP_REQUEST_INSTALL_PACKAGES` 改变会触发系统重新挂载导致隔离失效）\n\n## 5.0.1 (2020-12-15)\n\n- 修了在 Android 11 上新添加的“导出被隔离的文件夹”规则不会立刻生效的问题\n\n## 5.0.0 (2020-11-23)\n\n- 支持出厂 Android 11 的移除了 `sdcardfs` 的设备（如 Pixel 5，Pixel 4a 5G 等）\n- 在 Android 11，“导出被隔离的文件”使用 `mount` 而不是 `hard link` 实现（因为媒体存储无权访问链接文件）\n- 所有涉及 `untrusted_app` 域的跨进程通信均已使用 binder（许多部分被完全重写）\n- 几乎去除所有表明设备已 root 的痕迹\n- 将 `/data/adb/storage-isolation` 作为数据文件夹使用，如果没有问题你可以删除 `/data/misc/storage_redirect`\n- 讲出所有的变化很难 😶\n\n## 4.5.3 (2020-08-20)\n\n- 改变核心部分做法，应该不再会有先前版本的「适应 Android 11 的改变」带来的问题\n- 适应 Android 11 beta 3 的变化\n\n## 4.5.2 (2020-06-19)\n\n- 不让放任一个奇怪的错误<sup>**〔1〕**</sup>致使整个应用崩溃\n\n<sub><b>〔1〕</b>An error related to Retrofit + Kotlin coroutines, stacktrace is empty</sub>\n\n## 4.5.0 (2020-06-16)\n\n- 修复在 Android 11 上隔离早于用户解锁启动的应用会导致严重的问题\n- 当“增强模式”-“禁止系统重新挂载”启用时，隔离的应用的存储权限不再不可改变<sup>**〔1〕**</sup>\n- 增强模式：“禁止系统重新挂载”在 Android 11 上工作\n- 增强模式：“修复应用间交互”在 Android 11 上工作\n- 增强模式：移除“修复应用间交互”的 toast 提示（对于检查的使用场景，请检查 tag 为 \"SRHook\" 的 log）\n- 增强模式 v22.6：修复应用级别的“修复应用间交互”开关不起作用\n- 可自定义“导出被隔离的文件”规则标题\n- 改善“应用设置”页面性能\n- “相册预览”在 Android 11 上工作\n- 当应用开机启动，不要杀死由增强服务启动的进程\n- 提升目标 API 版本到 30\n- 改变了图标\n\n<sub><b>〔1〕</b>根据用户报告，这在 MIUI 这样的 💩 系统上可能会出现问题。</sub>\n\n> 根据用户报告及调查，“修复应用间交互”在一些高度修改的系统（至少包括 💩 一加）上不工作。我们将会在未来切换到一个完全不同的方案。\n\n## 4.4.1 (2020-05-01)\n\n- 修复“文件监视”页面卡顿\n- 修复“可访问文件夹”-“其他应用的文件”显示错误\n\n## 4.4.0 (2020-04-29)\n\n- 修复应用间交互：移除 \"startActivity hook\"<sup>**〔1〕**</sup><sup>**〔2〕**</sup>\n- 修复在一些情况下改变“默认隔离存储空间位置”会一直等待\n- 正确地实现“向上”（ActionBar 中的箭头）<sup>**〔3〕**</sup><sup>**〔4〕**</sup>（但很悲伤，甚至系统应用也没有做对 😰）\n- 为所有显示于系统栏下的列表修复 edge effect（几乎所有应用都没做对这个 😋）\n- 因为相册预览在 Android R 上坏掉所以暂时隐藏\n\n<sub><b>〔1〕</b>这会产生问题。</sub>\n<br><sub><b>〔2〕</b>在 Android 10+，暴露 `file` uri 会导致崩溃，垃圾应用应该已经做出改变。我们不再需要去“帮助”它们。</sub>\n<br><sub><b>〔3〕</b>根据<del>上古</del>规范，“返回”应导航至前一屏幕但“向上”应导航至逻辑上的上一级。例如，从 B 进入 A 的一个深层页面，“返回”返回到 B 但是“向上”去往 A 的上一层。（这也需要 B 做对）</sub>\n<br><sub><b>〔4〕</b>在 Android R 开发者预览版本中，Google 弄坏了这个“没人用的东西”，因此“向上”仍然像“返回”一样运作。</sub>\n\n## 4.3.1 (2020-04-05)\n\n- 添加一个简单一些的提交规则方式\n- 修了不能为非主用户的应用添加“可访问文件夹”-“其他应用的文件夹”规则的问题\n- 修了一些 UI bug\n\n## 4.2.3 (2020-03-24)\n\n- 解决与以 `setApplicationHiddenSettingAsUser` 为原理的冻结类应用一起使用时出现的问题\n\n## 4.2.2 (2020-03-22)\n\n- 修复应用设置中在线规则早于可访问文件夹加载导致网络较差时体验糟糕的问题\n\n## 4.2.1 (2020-03-21)\n\n- 改变“新应用通知”及“导出被隔离的文件”规则的通知的实现，这可以绕过 💩 MIUI 的系统 bug <sup>**〔1〕**</sup>以及另一个祖传小问题 <sup>**〔2〕**</sup>\n- 增强模块版本现在在线获取\n- “可访问文件夹模板”的应用列表现在正确支持多用户\n- 更多防呆设计\n\n<sub>**〔1〕** 在不明确的情况下，MIUI 会在 system_server 中对 startActivity 传入的 Intent 中的 Bundle 进行反序列化。如果 Bundle 中包含非系统的 Parcelable，则反序列化会失败且无法复原，应用只会收到空白的 Bundle。</sub>\n<br><sub>**〔2〕** 如果数据结构发生变化，且安装新版本应用后尚未更新核心服务，则出现通知时应用会崩溃。</sub>\n\n## 4.2.0 (2020-03-14)\n\n- 为启动较早的系统应用启用隔离不再会有问题（但是，以防万一，你仍需要[做好准备](./guide/enhanced_mode/install.html#无法进入系统（通常是由于隔离了系统组件）)）\n- 完全修好恢复备份\n- 修复特定的情况下应用失去响应（白屏）\n\n## 4.1.7 (2020-03-10)\n\n- “导出被隔离的文件”规则现在参与“修复应用间交互”功能的计算（需要重新启动受影响的应用才可以让改动生效）\n- 修复修改可访问文件夹模板不会立刻生效的问题\n- 修复由于系统更新导致的多用户支持坏掉\n- 为隔离重要系统应用及程序组的流程加入防呆设计\n\n## 4.1.6 (2020-03-06)\n\n- 可以使用内置 logcat 来取得开机 log（不再于启动时清除 log & 修复 UI 不响应）\n- 已卸载应用的“导出被隔离的文件”规则不再参与冲突检查\n- 修复一旦用户进入其他页面，“文件监视”就不再刷新的问题\n- 修复极少数的“文件监视”记录不显示的问题\n- 修复罕见的被隔离的应用不启动问题\n\n## 4.1.5 (2020-03-04)\n\n- 完全解决上个版本所解决的问题\n\n## 4.1.4 (2020-03-03)\n\n- 修复“禁止系统重新挂载”功能失效<sup>**〔1〕**</sup>\n\n<sub>**〔1〕** 此功能应该只有 MIUI 11（或许只有中国大陆版本？）需要</sub>\n\n## 4.1.3 (2020-03-01)\n\n- 再次调整启动核心服务的一部分的时机（在 MIUI 或许还有其他的奇奇怪怪的系统上，启动太早或太晚都会有问题，太难了（\n- 修复一个有关恢复备份的问题\n\n## 4.1.2 (2020-02-29)\n\n- 修复由 4.0.0 引入的部分人会出现购买信息丢失的问题\n- 添加“禁用导出被隔离的文件的通知”选项，因为在使用增强模式的“修复应用间交互”后通知没有意义（该选项仅对新用户默认启用）\n- 修复来自程序组的“导出被隔离的文件”规则在添加/更新/删除时可能出现问题\n- 修复恢复备份时部分应用无法被恢复的问题\n- 修复数个有关“修复应用间交互”的问题\n\n## 4.1.0 (2020-02-28)\n\n- 为避免问题，所有非普通应用（uid < 10000）将在本次升级时停用隔离（根据回报，隔离 uid 1000 的应用可能会在 MIUI, OnePlus Oxygen OS 等重度修改系统上产生问题）\n- 修复上个版本文件监视不工作\n- 修复上个版本可能的配置丢失\n\n## 4.0.0 (2020-02-28)\n\n- 修改应用名称为“存储空间隔离”，因为“重定向”十分容易让人误以为是旧时代的“重定向到 SD 卡”\n- 正确支持 Android 系统的 `sharedUserId` 机制（几乎所有部分都需要改动，上次更新到现在大部分时间都花费于此）\n- 核心服务在「非正常重新启动」后仍可正常运作\n- 修复在 Android 10 上关闭隔离后存储权限显示为允许但实际为不允许且无法改为允许的问题\n- 不再将 AOSP 应用视为已认证\n- 现在如果有人没事把 \"Android\" 文件夹重命名为 \"android\" 甚至改来改去，“导出被隔离的文件”功能也能正常运行（到底是什么人才会这么无聊）\n- 增强模式 v22：更早启动核心服务中的一部分，这可以解决为非常早启动的应用启用隔离可能会导致无法开机的问题（对，这又是仅限 💩 MIUI 的问题）\n- 增强模式及 Riru 版本号永远不再显示为未知\n- 若重新安装曾经启用隔离的应用，原先的设置会被正确地恢复（是否启用隔离的开关仍需要手动打开）\n\n## 3.2.2 (2019-12-22)\n\n- 修复一个有关恢复备份的问题\n\n## 3.2.0 (2019-12-18)\n\n- 修复使用了增强模式时为非常早启动的应用启用隔离可能产生问题（对，这又是「为了绕过 💩 MIUI 的问题做出的改动」产生的问题）\n- 几乎改了每一处的 UI 改进\n\n## 3.1.5 (2019-12-06)\n\n- 退回 3.1.4 中的一些改动，因为在另外一部分人上又有问题（\n\n## 3.1.4 (2019-12-05)\n\n- 修复一个启动过程的问题\n\n## 3.1.3 (2019-11-24)\n\n- 尝试规避“禁止系统重新挂载”功能可能造成“重启”的问题（注意，新的改变需要重新启动后才会生效）\n- 导出被隔离的文件（同步文件夹）功能会先删除目标文件夹中同名的文件，这是为了尝试避免一些应用进行数个重命名/移动等操作后“错误的”文件被导出的问题\n- 增加本地规则预置字串以供关闭在线规则或网络不可用时使用\n\n## 3.1.0 (2019-11-23)\n\n- 增强模式：“修复应用间交互”现在可以处理对“下载管理器”的请求\n- 修复在 Android 10 上存储权限可能没有正确授予的问题\n- 其他小 BUG 修复与 UI 改进\n\n## 3.0.0 (2019-11-21)\n\n- 重新设计多处 UI，降低理解难度\n- 重构多处 UI 相关部分，增加稳定性与流畅性\n- 增强模式 v21：增加“禁止系统重新挂载”功能以避免系统触发的重新挂载导致隔离失效（在 Android 9 以上可用）<sup>**〔1〕**</sup>\n- 增强模式：加回“修复应用间交互”中的修改传递的文件路径功能，但暂时只处理 `ACTION_VIEW`<sup>**〔2〕**</sup>，且不再经由存储重定向中转<sup>**〔3〕**</sup>\n- 重新设计在线规则，更加灵活\n\n<sub>**〔1〕** 此功能应该只有 MIUI 11 需要</sub>\n<br><sub>**〔2〕** 触发反序列化 `extras` 很危险</sub>\n<br><sub>**〔3〕** 即使我们什么也不做，原始行为在 Android 10 上已经会造成崩溃，我们没有必要越庖代俎为劣质应用「修复问题」</sub>\n\n## 2.1.5 (2019-10-30)\n\n- 修复一些 UI BUG\n\n## 2.1.4 (2019-10-29)\n\n- 改进一些核心部分的实现\n- 修复一些 UI BUG\n\n## 2.1.3 (2019-10-23)\n\n- 绕过在 OnePlus 的 Android 10 上使用自动暗色主题会崩溃的问题（这个问题由 OnePlus 的引起）\n\n## 2.1.1 (2019-10-23)\n\n- 修復如果核心进程启动晚于启用的应用则该应用可能无法启动的问题\n\n## 2.1.0 (2019-10-22)\n\n- 简化允许访问来自其他应用的文件流程，现在只要是由其他应用创建的文件都可以在“属于其他应用的文件夹”中选择\n- 在每次应用启动时检查并授予权限，这可能解决由 MIUI 11 随机篡改权限造成的问题\n- 绕过在 Meizu 设备上使用内置 su 时核心工作进程会被杀死的问题\n- 临时移除“修复应用间交互”中的修改传递的文件路径功能，因为这个功能在使用插件化或热修复技术（常见于来自中国大陆地区的应用）的应用中会产生问题，且目前主流应用应该都已使用 Content Provider 与其他应用共享文件，移除此功能应该影响不大\n- 其他 BUG 修复与大量 UI 改进\n\n## 2.0.1 (2019-09-27)\n\n- 修复“共享文件夹”规则实际没有生效\n\n## 2.0.0 (2019-09-27)\n\n- 对“共享文件夹”及“同步文件夹”规则进行问题检查（有问题的规则会被删除有问题的部分或禁用），在下个版本会针对这个这个问题提供更加详细的提示及教程\n- 修复数个有关“同步文件夹”规则的问题\n- 修复独立“修复应用间交互”开关坏掉\n- 增强模式 v20.1：修复“修复应用间交互”功能在 OnePlus Android 10（可能还有其他）上的问题\n- 大量 UI 改进\n\n## 1.9.1 (2019-09-09)\n\n- 修复“修复应用间交互”可能没有工作的问题\n- 增加半透明状态栏及导航栏选项\n- 修复数个 UI bug\n\n## 1.9.0 (2019-09-08)\n\n- 增强模式 v20.0：修复使用 [Adoptable Storage](https://source.android.com/devices/storage/adoptable) 时安装在外置存储卡的应用无效的问题\n- 增强模式 v20.0：更改“修复应用间交互”功能的实现方法，不再会被“Xposed Taichi”破坏，同时也可能会解决一些其他的问题\n- 增强模式 v20.0：“修复应用间交互”可单独为每个应用开关\n- 修复备份功能不能还原部分配置的问题\n- 在 Android Q 上自动允许 `OP_REQUEST_INSTALL_PACKAGES`（因为其发生变化时会触发系统重新挂载）\n\n## 1.8.3 (2019-08-30)\n\n- 修复一些 UI bug\n- 修复“基础模式”下的一个重大问题\n\n## 1.8.2 (2019-08-27)\n\n- 处理特殊系统应用（appId < 10000 或 appId > 19999, appId = uid % 100000）\n- 不为特殊系统应用锁定权限\n- 其他 bug 修复和 UI 改进\n\n## 1.8.1 (2019-08-26)\n\n- 改进选择“可访问文件夹”流程\n- 可直接为“可访问文件夹模板”选择使用的应用\n- 修复在 Android Q 上启动服务时对已启动的应用的重定向会失效问题\n- 修复长时间停留在主界面 CPU 占用会越来越高问题\n- 修复使用 API（暂未公开）的应用崩溃的问题\n- 其他 bug 修复和 UI 改进\n\n## 1.8.0 (2019-08-17)\n\n- 选择“可访问文件夹”时可同时选择多个模板及自定义\n- 增加“文件夹分析”功能，获知隔离存储空间中文件夹大小\n- 可访问文件夹中选择的文件夹不存在时会自动建立\n- 一些些 UI 改进和 bug 修复\n\n## 1.7.5 (2019-08-06)\n\n- 修复“同步文件夹”功能坏掉\n\n## 1.7.4 (2019-08-05)\n\n- 在 Android Q 上使用 `FLAG_PERMISSION_SYSTEM_FIXED` 来固定权限\n- 为华为设备提供解决方法，[详见此处](./guide/compatibility/huawei.html)\n- 修复“同步文件夹”功能没有尝试处理“从目标文件夹移走文件”事件\n- 改进英语翻译\n- 其他小改动\n\n## 1.7.2\n\n- Fix \"Code 5\"\n- Other bug fix\n\n## 1.7.0\n\n* Basic mode now works on Android Q beta 4\n* Correctly handle hide/unhide (commonly used by \"Freeze\" apps)\n* Change target SDK version to 29 (Android Q)\n\n## 1.6.12\n\n* Fix app list not refreshed after restoring backup\n* Use a more reliable method to monitor app install/uninstall\n* Notify user if no browser app available when opening help documents\n* Fix a bug related \"Fix app interaction issues\" \n* Other bug fix\n* UI improve\n\n## 1.6.9\n\n* Fix Enhanced mode not work for apps starts early than core service\n\n## 1.6.8\n\n* Fix apps not starting on new users\n* Support Android Q beta 3 (including Enhanced mode)\n* Remove the ability to choose \"Android/sandbox\" as isolated storage path since from Q beta 3 the system sandbox is only used for apps which declared support the sandbox\n\n## 1.6.7\n\n* Clear config (app info - storage - clear/manage data) feature dose clear all configs now\n* Filter duplicates or incorrect mounts in the final stage to avoid problems from user misuse\n* Fix \"Fix app interaction issues\" may incorrectly handle files in `Android/data(media, obb)/package`\n\n## 1.6.6\n\n* Fix app interaction issues (Enhanced mode): Grant content uri permission\n* UI improve\n\n## 1.6.4\n\n* Fix app interaction issues (Enhanced mode): Always convert file uri to content uri on Android Q\n* Enhanced mode: remove disable file uri expose check since it is meaningless\n* Allow choosing \"Android/sandbox\" as isolated storage path on Android Q\n* Other bug fix\n\n## 1.6.3\n\n* Enhanced mode works on Android Q\n* Enhanced mode: force disable file uri expose check for Android Q system ui\n* Improve App settings UI\n* Try fix config lost (should be extremely rare), add \"Debug info\" for users to investigate this problem\n* Fix storage permission can't be revoked if redirect is already disabled\n\n## 1.6.2\n\n* Add \"View gallery as this app\", you can learn which photos the app can access\n* Bug fix & UI improve\n\n## 1.6.0\n\n* Works on Android Q DP2 (enhanced mode not supported yet)\n* Change behavior, mount Android/media/xxx & Android/obb/xxx by default\n* Huge UI improve\n* Fix \"Fix app interaction issues\" never worked on some devices\n\n## 1.5.7\n\n* Continue fixing bugs caused by \"Fix app interaction issues\"\n* Continue renaming options\n\n## 1.5.6\n\n* Fix new storage permission method breaks on MIUI\n* Fix \"Fix app interaction issues\" feature causes app breaks on some situations (if extra contains Parcelables from non-BootClassloader)\n\n## 1.5.5\n\n* (Android 6.0-7.1) Fix \"Fix app interaction issues\" feature cause app crash or all media not shown\n* Continue renaming options, app name would even change in the future\n* Reduce extra app launching time\n  \n  On my OnePlus 3T, average extra time reduced from 0.3s to 0.16s\n  \n  * Enforce storage permission with API (do not need check everytime), save average 0.04s\n  * (only on 7.0+) Limit \"File monitor\" hook target, save average 0.1s\n  \n## 1.5.3\n\n* Enhancement module v19, please upgrade as soon as possible\n\n  * \"Fix app interaction issues\": try bypassing the problem that apps use \"Tencent app protect\" (腾讯乐固) will crash (v19)\n  * \"Fix app interaction issues\": fix some media are filtered incorrectly (app 1.5.1, v19)\n  * \"Fix app interaction issues\": fix app may crash when \"Access files from other redirected app\" rules enabled (v18.1)\n\n## 1.5.0\n\n* New Enhancement module v18\n  \n  Rewrite \"Fix file uri\" feature, upgrade to \"Fix app interaction issues\" feature \n  \n* UI change\n* Rename some options, reduce the understanding difficulty\n\n## 1.4.9\n\n* Fix \"Synced folders\" feature is broken in 1.4.8\n\n## 1.4.8\n\n* Fix regex check of \"Synced folders\" rules is not proceed when enabling the rule\n* Revoke app storage permission automatically when disabling redirect\n* Other bug fix\n\n## 1.4.7\n\n* Fix Enhancement module installation error reporting\n* Fix Google purchase issue reporting\n* Bad connection with Google Play will not freeze the whole app forever (but 5s)\n* Fix \"Fix file uri\" feature in Enhancement module may sometimes crash redirected app \n* Correctly report some type of error on start\n* Other bug fix\n\n## 1.4.6\n\n* Improve Enhancement module installation detection and provide solution\n* Improve \"Invalid license\" page\n* Bug fix\n\n## 1.4.4\n\n* Bug fix\n\n## 1.4.2\n\n* Report Enhancement module not correctly installed\n* Improve home\n\n## 1.4.1\n\n* Fix license check\n\n## 1.4.0\n\n* New home page\n* Rename/re-layout options, reduce the understanding difficulty\n\n  * \"Non-redirect folders\" -> \"Read/writable folders in real storage\"\n  * \"Link\" -> \"Synced folders\"\n\n* New Enhancement module v17, not more \"I can't open redirected apps\"\n* Fix tons of bugs\n\n## 1.3.3\n\n* Fix bug of Enhance module v16\n\n## 1.3.2\n\n* Enhance module v16, fix a problem related to passing file uri\n  (Example: can't open a received file in WeChat)\n* New native starter (for some strange devices without executables like `chmod`, `rm`)\n* Fix bugs related to link feature\n* Other minor bug fix\n\n## 1.2.2\n\n* Fix mask template for link rule editor\n* Add \"Link function only\" filter in \"Logcat\"\n* Minor bug fix\n\n## 1.2.1\n\n* Add \"Kill Media Storage on start\" option\n  (on some devices, Media Storage can use all CPU on boot, kill it can solve the problem\n  (it can be started by other apps later))\n* Add mask template for link rule editor\n* Try to detect no log\n* Minor bug fix\n\n## 1.2.0\n\n* Add \"Shared folder\" to solve the problem that files created by\n  a redirected app can't be used by another redirected app\n* Refreshed detail UI\n* Enhanced \"Redirect storage viewer\"\n* Enhanced filter for \"File monitor\"\n* Enhance module v15, fix the problem that redirect apps can't move files between specific folders\n  (Example: bilibili can't save gif)\n* Minor bug fix\n\n## 1.1.4\n\n* Enhanced \"Non-redirect folders\" template mechanism\n* Show conflicting rule info\n\n## 1.1.2\n\n* Simplified detail UI\n* Try to support other su, confirmed support MagiskSU, SuperSU, LineageOS addonsu now\n* Fix the problem that server may send wrong progress to client\n  when change \"Default redirect target\"\n* Delete redirected app config after that app uninstall\n* Improve app list performance\n* Improve chooser dialogs\n* Improve File monitor\n* Add non standard behavior check (use file monitor data)\n\n## 1.0.2\n\n* Fix UI not refreshed when add link rules online\n* Fix the problem that \"You have already own this item\" happens on some Google Play users\n\n## 1.0.0\n\n* Add \"Non-redirect folders\" template, you can create different templates\n  for different situations and apply them quickly\n* Enhance module v14, changes behavior, may avoid some special problems on\n  some devices\n* Bug fix\n\n## 1.0.0-rc9\n\n* New logcat UI\n* Fix unpaid state check\n* Migrate to AndroidX library\n\n## 1.0.0-rc8\n\n* Improve user experience\n* Minor bug fix\n\n## 1.0.0-rc7\n\n* Fix \"Launch\" button not work\n\n## 1.0.0-rc6\n\n* Improve user experience\n* Bug fix\n\n## 1.0.0-rc5\n\n* Add White / Light blue theme\n* Try to hide overlay packages\n* Fix can't open installer in file browser\n* Fix some link rules can't be added\n* Bug fix\n\n## 1.0.0-rc4\n\n* Add manually set /data/media path for some special devices\n* Bug fix\n\n## 1.0.0-rc3\n\n* Fix Android/data can be chosen as a \"Non-redirect folder\"\n* Bug fix\n\n## 1.0.0-rc1\n\n* New theme\n* New detail UI\n* Add local link rule\n* Multi-user support\n* Fix backup bug, but backup files created before 1.0.0-rc1 is unavailable\n* Try to detect real internal storage path\n\n## 0.18.2-beta\n\n* Fix bug\n\n## 0.18.0-beta\n\n* \"Non-redirect folder\" (old \"Standard folder\") is now customizable like \"Redirect target folder\"\n* Add Backup & restore\n* Works with LineageOS's addonsu, but some non-core feature may break, still recommended to use Magisk\n* Fix crash when change filter in the main list\n* Fix redirected files may not be moved when change redirect target folder in some cases\n\n## 0.17.4-beta\n\n* Fix link feature not on some (old? special?) devices\n* Try to fix owner of linked files' is 0 on older Android system (chown ourselves)\n\n## 0.17.3-beta\n\n* Fix a critical bug that if an app's redirect target is set different\n  from the default, it will not able to access files in public folders\n* Fix others bugs in 0.17.x\n\n## 0.17.1-beta\n\n* Add set redirect target folder (globally and pre-app)\n* Add app installed notification\n* Also kill by uid when force stop package (for OnePlus stock ROM)\n* Improved \"Share helper\"\n* Bug fix\n\n## 0.16.4-beta\n\n* Add file stat for Redirect storage viewer\n* Fix the problem that anyone is displayed as purchased\n* Auto clean old server files\n* Try to \"fix\" IAP problem \"You have already own this item\"\n* Link files from target to source when enabling link rules\n\n## 0.16.2-beta\n\n* Enhanced File monitor: load more & filter by path / app\n* Force grant storage permission for redirected apps\n* Try to fix bug of link function (when create and delete files in a very short time)\n* Create \".nomedia\" file in Android/data/xxx automatically\n* Add shortcut for File monitor (Android 7.1+)\n* Fix crash when open help if no browser app installed\n* Add more tips\n* Fix bugs in 0.16.1 / 0.16.2\n\n## 0.15.8-beta\n\n* Files downloaded by redirected apps can be managed in Android's Files (DocumentUI) app\n* Fix log parse (only some special ROM)\n* Add \"Show disabled apps\" filter\n* New app list style\n* In-app logcat now catches logs from more sources\n\n## 0.15.4-beta\n\n* Fix reboot when new file created in folders monitored by link function (only on 8.0)\n* Fix a bug of file monitoring function of the link function\n\n## 0.15.2-beta\n\n* Try to fix crash on boot (only some users)\n* Fix log parse (only some special ROM)\n* Auto shrink file monitor database file\n\n## 0.15.1-beta\n\n* Enhance module v12.1\n\n  Fix problem that all apps unable to access the storage (only appears on some devices), but it brings some minor problems (only happens on limited situation), check Help for detail.\n\n* Other minor changes\n\n## 0.15.0-beta\n\n* New Enhance module (check Settings and Help)\n* File monitor: monitor file access in public storage (requires \"Enhance module\")\n* Try to fix bugs in 0.14.3\n\n## 0.14.3-beta\n\n* Try to fix bugs in 0.14.1 / 0.14.2\n* Magisk module v10 (check Help & support)\n\n## 0.14.1-beta\n\n* Provide new Magisk module to solve the problem that redirected apps still create files sometimes, check Help & support for detail\n* New native daemon\n* Adapt Magisk v16.4\n* Improve UI\n* App list will be loaded correctly now even if instant app is installed (Android 8.0's bug)\n\n## 0.12.13-beta\n\n* Link rule: fix the problem that some files are skipped\n\n## 0.12.12-beta\n\n* Fix the problem that some processes are ignored on **some special ROMs**\n* Link rule: ignore file which extension ends with _tmp_ or _temp_ by default\n\n## 0.12.11-beta\n\n* Some bug fix\n\n## 0.12.7-beta\n\n* Fix the problem that some process is not redirected (from 0.12.6)\n* Link rule: handle file downloaded notification by our app\n\n## 0.12.6-beta\n\n* Should work on Android P DP1\n* Link rules ignore .tmp / .temp by default\n* Some minor changes\n\n## 0.12.5-beta\n\n* Update Magisk module (download from Help & support)\n* Some minor changes\n\n## 0.12.4-beta\n\n* New link rules UI\n* Mark outdated (not exists in online configuration) link rules\n* Try to avoid some magic\n* Add \"Share helper\"\n\n## 0.12.3-beta\n\n* Add more log for starter\n* More core files to /data/adb\n* Try to avoid strange behavior on some devices when using Magisk module\n\n## 0.12.1-beta\n* **The core feature should works perfectly on all devices**\n* Provide Magisk module for starting before all apps (see Help & support)\n\n## 0.12.0-beta\n\n* Fix major issue on some devices\n* Add tip when log may be disabled\n* Linked files will only be deleted when redirected app is running in the foreground\n\n## 0.11.2-beta\n\n> Version 0.11.2 changed some implementation details, to avoid some magic problems on users who have problems using version 0.11.0\n\n* Should work on more devices now, to the user who still have problem, the problem should not break all things\n* Storage permission (both runtime permission and appops) will be automatically grant to redirected apps (to avoid magic problem)\n\n## 0.11.0-beta\n\n> In 0.11.0 and later version, we use a completely different method of implementation. The problem that hard-coded `/sdcard` cannot be redirected is solved.\n> If you have problem using the new version, please contact us for help.\n\n* A completely different implementation, guarantee that all files will be redirected (**Read help in \"Help & support\" for more detail**)\n* Server can be restarted without rebooting (**Reboot is required if upgrade from 0.9.x**)\n* Add redirected file browser\n* Add logcat\n* Add detailed help\n* Add \"verified app\" mark which means the app will never write files in non-standard dictionaries\n* Remove \"Block writing file\" feature since it is unnecessary now\n* Fix bug about link"
  },
  {
    "path": "storage_redirect/zh-hans/download.md",
    "content": "# 下载\n\n**需求:** 已 root 的 Android 6.0 以上设备\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.redirectstorage)（自动选择架构）\n\n[Coolapk](https://www.coolapk.com/apk/moe.shizuku.redirectstorage)（arm64 版本）\n\n[GitHub](https://github.com/RikkaApps/StorageRedirect-assets/releases)（全部架构，**三星用户请在这里下载 arm 版本**）\n\n::: warning\n**三星用户**\n\n由于三星设备内核的一些不明原因，**三星设备只能使用 arm 版本**。\n:::"
  },
  {
    "path": "storage_redirect/zh-hans/guide/README.md",
    "content": "# 介绍\n\n截至本文编写的时间（2023-03-06），在 Android 系统中应用对公共存储空间的滥用仍然是一个没有解决的问题。\n\n存储空间隔离致力于在尽可能小或不影响应用功能的前提下，解决这一问题。\n\n要清楚地说明这个问题，我们不得不先引入一些技术性的概念。\n\n### Android 系统对于存储空间的设计\n\nAndroid 系统为应用提供了两大类共三处存储其文件的位置，它们分别为：\n\n#### data 区域\n\n对应的文件夹：\n\n- `/data/user/<user_id>/<package_name>`\n- `/storage/emulated/<user_id>/Android/data/<package_name>`\n\n> `<user_id>` 为用户 ID，涉及 Android 的多用户/工作资料机制，与本文主题无关。\n>\n> `<package_name>` 为应用的唯一 ID，即俗称的“包名”。\n\n这两个文件夹应该用于存储应用自身的数据，具有如下特点：\n\n- 应用无需请求权限即可使用\n- 只有应用自身可以访问\n- 在卸载应用或清除应用数据后会被删除\n\n> `/storage/emulated/<user_id>/Android/data/<package_name>` 与 `/data/user/<user_id>/<package_name>` 的用处相同。它的存在是因为一些历史原因：在 Android 4.x 及更早的时代，设备自带的存储空间通常非常小，外置 SD 卡会被用来扩展存储空间，此处便也被用作存储应用自身的数据。\n\n#### 内部存储空间\n\n对应的文件夹：\n\n- `/storage/emulated/<user_id>`\n\n此处应存放对用户有用的文件，例如用户在应用中保存的图片。Android 系统提供了 `DCIM`、`Download`、`Pictures` 等公共文件夹用于分门别类地保存照片、下载的文件等。此处还可以被成为“共享存储空间”、“公共存储空间”等。\n\n具有如下特点：\n\n- 需要存储权限才可以读取\n- 需要存储权限才可以写入<sup>**〔1〕**</sup>\n- 拥有存储权限的应用可以读取其中所有的文件，包括由其他应用、用户写入的文件\n- 在卸载应用或清除应用数据后，应用写入的文件不会被删除\n\n<sub>**〔1〕** 在 Android 11 后有变化，请参考下文</sub>\n\n### 应用访问文件的方式\n\n除了最基本的直接通过文件路径访问以外，Android 系统还提供了其他几种方式。\n\n* 媒体存储\n\n  媒体存储是一个系统应用，其内部有一个包含内部存储空间中所有文件信息的数据库。最常见的用例是，从媒体存储查询所有的图片文件。读取、写入文件也可以通过媒体存储进行。\n\n* 存储访问框架（Storage Access Framework，简称 SAF）\n\n  SAF 是一个 Android 4.4 起添加的功能。借助 SAF，用户可以从一个统一的由系统提供的 UI 进行打开文件、保存文件等操作。应用程序还可以自己成为一个提供程序，其他使用 SAF 的应用便可使用它。\n\n  SAF 的好处是应用仅可使用由用户选择的文件、统一的 UI、应用无需请求权限等等。\n  \n  但是，多数应用还是更倾向于请求存储权限后自己实现需要的功能。\n\n### 什么是应用滥用存储空间的问题\n\n对存储空间的滥用是对“内部存储空间”的滥用。\n一些应用或一些 SDK 会希望自己的数据文件在卸载后不会被删除，因此它们会选择“内部存储空间”写入其数据文件。\n\n如果应用有“发送图片”、“保存文件”等功能，用户很多时候就不得不授予应用存储权限。它们就会借此在“内部存储空间”写入一大堆奇奇怪怪的文件夹（见下图）。久而久之用户的存储空间将变得混乱无比。\n\n::: details 例子\n\n许多滥用存储空间的应用建立一堆奇奇怪怪的文件夹，甚至以“SystemConfig”命名来让用户误以为是系统文件。\n\n<img :src=\"$withBase('/images/chaos_storage.png')\" alt=\"例子\">\n:::\n\n#### Android 11 添加的分区存储（Scoped storage）\n\n许多人认为分区存储能够解决这个问题，但是事实并非如此。\n\n受分区存储限制的应用在使用公共存储空间时的行为会发生如下的变化：\n\n- 仅可在公共文件夹中写入对应类型的文件（但是系统只会检查文件名称是否符合规则）\n- 不需要任何权限即可在公共文件夹中写入文件（这比以前更加宽松！）\n\n显然我们可以发现，仍然可以写入任意文件，唯一的区别仅仅是需要调整保存文件的位置到某个公共文件中，调整文件名来欺骗系统。\n\n此外，分区存储仅作用于以 Android 11 或以上版本为目标平台的应用（即 Target API ≥ 31）。不在 Google Play 上架的应用或停止更新的老应用不会受到限制。\n\n### 解决这个问题\n\n为了解决上面这个问题，我们创造了这个应用——存储空间隔离。\n\n用户可以为特定的应用启用隔离。应用所使用的“内部存储空间”实际将变为 `/storage/emulated/<user_id>/Android/data/<package_name>` 中的一个文件夹。因此，真正的“内部存储空间”将不会被污染，其创建的文件也会在卸载后得以删除。\n\n我们提供了多种机制来保证被隔离的应用在需要使用“内部存储空间”中的文件时工作正常。请阅读后续的文档。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/advanced/shared_user_id.md",
    "content": "# 程序组\n\nAndroid 系统的 Shared User ID 机制允许多个应用享有相同的 Linux user ID 及 Android 权限，相互访问文件甚至运行在同一个进程。这些应用需要有具有相同签名。Shared User ID 不可在安装后更改。为了简化理解难度，我们在存储空间隔离内称 Shared User ID 机制为程序组。\n\n这意味着：\n\n* 一些没有存储权限的应用实际可以使用存储空间\n* 多个应用可以运行在同一个进程\n\n隔离作用于进程层面。在 v4.0.0 之前的版本中，只有 package name 被用作判断，这显然会产生问题。\n\n### 例子\n\n媒体存储、下载管理器、下载管理器 UI、MTP 主机拥有同一个 Shared User ID `android.media`，其中媒体存储和下载管理器都设定了 `android:process=\"android.process.media\"`。因此媒体存储和下载管理器运行在同一个进程。\n\n在 MIUI（或许还包括其他重度修改的系统）中，下载管理器有滥用存储空间的行为，因此用户会选择为其启用隔离并只允许其访问 `Download` 文件夹。但由于媒体存储也运行同一进程，因此媒体存储实际也只能访问 `Download`，这会造成用户相册无法更新。\n\n另外，Shared User ID 机制可以做到使没有存储权限使用存储空间。同样是 MIUI（或许还包括其他重度修改的系统），用户会没有机会为这样的应用启用隔离，因为在旧版本中它们不会被展示。\n\n因此 v4.0.0 后让相同 Shared User ID 的应用使用相同的设定可以解决这个问题。\n\n### 行为\n\n假设有两个应用 `com.example` `com.example2`，它们的 Shared User ID 是 `example`。\n\n* 使用相同的设定（在内部被视为“同一个应用”）\n* 隔离存储空间位置位于 `Android/data/shared-example` 中\n* 可相互访问应用专有文件夹"
  },
  {
    "path": "storage_redirect/zh-hans/guide/advanced/technical_details_export_isolated_files.md",
    "content": "# 技术细节（导出被隔离的文件）\n\n假设有一个应用 `com.example` 保存图片至 `images` 文件夹。建立了一条来源文件夹 `images`，目标文件夹 `Pictures/Example` 的规则。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard      <---- com.example 的隔离存储空间\n│       └───images  <---- 保存图片的位置（来源文件夹）\n│           ├───1.jpg\n│           └───...\n└───Pictures\n    └───Example     <---- 导出后的位置（目标文件夹）\n        ├───1.jpg\n        └───...\n```\n\n建立规则后，`Android/data/com.example/sdcard/images` 文件夹会被使用 [`inotify`](http://man7.org/linux/man-pages/man7/inotify.7.html) 监视并遵循如下的规则将其中的文件使用 [`link` (hard link)](http://man7.org/linux/man-pages/man2/link.2.html) “同步”至 `Pictures/Example`。\n\n因为使用 hard link，所以只会占用一份存储空间。其他 app 或系统可能会因为没有正确地处理这样的情况而错误地回报使用情况。\n\n规则的行为：\n* 在来源文件夹中建立文件/移动文件至来源文件夹：link 至目标文件夹\n* 删除/移出来源文件夹中的文件：若应用在前台则同时删除目标文件夹中的文件；若不在前台则什么都不做（这是为了避免用户/系统/第三方应用操作来源文件夹而导致文件丢失）\n* 在目标文件夹中建立文件/移动文件至目标文件夹：在下次核心服务启动时 link 至来源文件夹\n* 删除/移出目标文件夹中的文件：删除来源文件夹中的文件"
  },
  {
    "path": "storage_redirect/zh-hans/guide/compatibility/README.md",
    "content": "# 概览\n\n* [三星](./samsung.md)\n* [魅族](./meizu.md)\n* [小米（MIUI）](./miui.md)\n* 其他\n\n  * log 被关闭问题\n\n    在“开发者设置”中检查 log 是否开启。另外，据用户反馈，在华为 EMUI 上 log 默认被关闭。如果你在使用 EMUI，请自行查询如何在 EMUI 上开启 log。\n\n    或者，最简单的方式，使用 [增强模式](./../enhanced_mode/)。\n"
  },
  {
    "path": "storage_redirect/zh-hans/guide/compatibility/meizu.md",
    "content": "# 魅族\n\n如果你可以使用 Magisk，你不会遇到问题。\n\n如果你不能使用 Magisk，不要为系统的“设置”应用（或其所属的[程序组](./../advanced/shared_user_id.html)）启用隔离。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/compatibility/miui.md",
    "content": "# 小米（MIUI）\n\nMIUI 有一系列**默认启用**的限制。然而这些限制过于离谱，应用正常的功能经常因此被破坏。\n\n更令人生气的是，这些限制由 MIUI 的在线规则控制，并且对于微信这样在中国大陆地区流行的应用不会开启。\n\n## “在后台弹出界面”权限默认拒绝\n\n“在后台弹出界面”权限是一个由 MIUI 添加的权限，**默认为拒绝**。\n\n这是非常离谱的，因为拒绝该权限会**破坏应用的正常行为**。强烈建议你为所有设计优良的应用允许该权限。\n\n### 被破坏的功能\n\n1. 轻触“导出被隔离的文件”规则的通知无法打开文件\n2. 从 Google Play 购买时出现“与 Play 商店交互期间出现错误”\n\n### 解决方法\n\n1. 打开“存储空间隔离”的应用信息\n2. 轻触“其他权限”（对于 MIUI 中国大陆版本是“权限”或“权限管理”）\n3. 将“在后台弹出界面”改为允许\n\n对于无法打开文件的问题，你可能还需要为负责打开文件的应用允许“在后台弹出界面”。\n\n对于 Google Play 购买问题，你还需要为 Google Play 允许“在后台弹出界面”。\n\n## MIUI 的省电默认启用\n\n对于设计优良的应用，使用 MIUI 的省电功能**不会节省更多电量**，相反一些功能可能会被破坏。\n\n### 被破坏的功能\n\n尚不明确。\n\n### 解决方法\n\n1. 打开“存储空间隔离”的应用信息\n2. 点击“省电策略”\n3. 选择“无限制”\n"
  },
  {
    "path": "storage_redirect/zh-hans/guide/compatibility/samsung.md",
    "content": "# 三星\n\n由于未知原因，在部分三星设备上，以 root 用户中执行 64 位可执行程序，其中 `exec` 函数必定会 `Permission denied`。\n\n解决方法很简单，卸载后安装 [arm 版本](./../../download.html)。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/contribute.md",
    "content": "# 贡献在线规则\n\n目前需要人工在 GitHub 建立 issue。请按照下面的步骤进行。\n\n1. 如果你没有 [GitHub](https://github.com/) 账号，创建一个\n2. [建立新的 issue](https://github.com/RikkaApps/StorageRedirect-assets/issues/new?template=new_rule_json_zh-CN.md)\n3. 按照 issue 中的说明填写"
  },
  {
    "path": "storage_redirect/zh-hans/guide/enhanced_mode/README.md",
    "content": "# 为何增强模式是必要的？\n\n-----------------------\n\n增强模式提供以下功能：\n\n1. 不再需要依赖 `logcat` 侦测 app 进程创建\n   - 规避由于日志可能延后而导致有一小段时间应用不会被隔离的问题\n   - 规避 log 被关闭的问题（如 Huawei EMUI 开机时禁用 log ）\n2. 开机启动\n   - 规避定制系统禁止开机启动的问题（包括但不限于 MIUI）\n3. 禁止系统重新挂载\n   - 规避定制系统的行为触发重新挂载导致隔离失效（如 MIUI 11）\n4. 记录应用访问文件行为\n5. 修改媒体存储及下载管理器的行为，应用不能通过它们读取/写入已规定不能访问的文件夹\n\n## 性能影响\n\n“增强模式”只带来可以忽略不计的性能影响。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/enhanced_mode/install.md",
    "content": "# 安装\n\n增强模块要求您的设备首先安装 Magisk。您可以从 [GitHub](https://github.com/topjohnwu/Magisk) 了解有关 Magisk 的更多信息。\n\n:::tip 提示\n从 Magisk v24 起（于 2022-01-26 发布），在线仓库被移除。您只能直接下载 zip 后在 Magisk 中安装。\n:::\n\n## Zygisk\n\n您可以在开启 Zygisk 后使用 Zygisk 版本的增强模块（需要 v7.0.0 及以上版本的存储空间隔离）。\n\n* [模块](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets)（选择 Zygisk 版本）\n\n### 关于 Zygisk\n\nZygisk 是 Magisk v24 添加的功能。它与 Riru 在最终目的上类似，但细节与实现方面不同。\n\nZygisk 具有排除列表（DenyList）功能，在开启遵守排除列表（Enforce DenyList）后，Zygisk 不会为列表中的应用加载 Zygisk 模块。对于存储空间隔离，列表中的应用程序不能隔离。请注意，**排除列表不是隐藏功能，它甚至不能隐藏 Zygisk 自身的存在**。\n\n**排除列表是一个脱离实际的功能**，因为人们显然会又想要使用模块又想要隐藏。隐藏模块也要求不能开启遵守排除列表，否则隐藏模块也会因为不被加载而不能工作。\n\n简而言之，使用专门的隐藏模块 Shamiko 来隐藏，永远不要启用遵守排除列表。\n\n### 关于 Shamiko\n\nShamiko 是一个由其他人开发的隐藏模块。它可以隐藏 Magisk SU、Zygisk 自身及 Zygisk 模块。\n\nShamiko 借用了 Magisk 的排除列表。也就是说 Magisk 的排除列表是 Shamiko 的排除列表，但是为了让 Shamiko 生效你不能打开 Magisk 的遵守排除列表选项。这有些令人困惑，但是就是这样的。\n\n在 2022-02-02 以后在[这里](https://lsposed.github.io/)下载 Shamiko。\n\n## Riru\n\n如果您使用旧版本的 Magisk 或是不使用 Zygisk，则还需要安装 Riru。请下载 Riru 和 Riru 版本的增强模块并在 Magisk 中安装。\n\n* [Riru](https://github.com/RikkaApps/Riru/releases)\n* [模块](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets)（选择 Riru 版本）\n"
  },
  {
    "path": "storage_redirect/zh-hans/guide/faq/cant_find_app.md",
    "content": "# 无法找到一些应用\n\n只有请求了读取<b>和</b>写入存储权限的应用会被显示（换句话说，只请求读取存储权限或没有请求存储权限的应用不会显示)。\n\n## 使用 root/adb 的应用\n\n使用 root 或 adb 的应用可以直接以 root 或 adb 身份访问存储空间而不受自身权限限制。\n\n> 此处的使用 adb 的应用不包括要求使用 adb 授予权限（`pm grant`）或进行类似操作的应用。\n\n## 使用 Xposed 的应用\n\n使用 Xposed 的应用通过其注入的应用使用存储空间，即实际访问存储空间的是其注入的应用而不是 Xposed 模块应用本身。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/faq/how_to_document.md",
    "content": "# 如何使用文档（文件）应用\n\n文档应用是 Android 系统的一部分，好处是使用者可以借此方便地从各种来源（任何实现了 DocumentProvider 的应用，如 Google Drive）存取文件。\n但坏处是文档应用可能有些难用。此帮助将教你如何使用文档应用。\n\n首先，如果你是第一次使用文档应用，默认设备的内置存储不会显示。\n你需要在右上角三点菜单选择“显示内置存储”来显示内置存储。\n\n接着，你需要知道通过右滑或点击左上角可以切换当前的位置。如果你首次使用，默认位置可能是“最近”，此位置无法创建文件，你需要选择你想要位置才可以保存。\n\n## 找不到文档应用？\n\n> 文档应用的包名是 `com.android.documentui`\n\n### 使用高度定制的系统\n\n在部分高度定制的系统上（如 MIUI），文档应用可能会被禁用甚至删除。\n你需要自行查找如何解决该问题。\n\n### 被禁用\n\n请前往系统设置-应用中寻找到文档应用并启用。\n\n### 被删除\n\n文档应用是 Android 系统的一部分。如果你发现你使用的系统确实删除了文档应用，**强烈建议你换用其他系统**，因为删除重要的系统组件是很荒谬的。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/faq/how_to_report_problems.md",
    "content": "# 回报问题\n\n该文档将教你如何回报问题。\n\n> 对于仅限于特定应用的问题（如无法在应用中找到图片），大概率是设定不正确，请先自行尝试阅读其他文档了解如何正确设置。\n\n1. 确认你正在使用最近的版本的应用\n2. 描述应用版本（例如 v4.1.6.r2361）\n3. 清晰地描述你的问题\n4. 附上问题出现期间的 log（如果可以，指出问题发生的大概时间）\n5. 发送至 [support@rikka.app](mailto://support@rikka.app)\n\n如果回报不符合要求，很大几率不会收到回复。\n\n### 如何抓取 log\n\n你可以使用应用内的 logcat（主界面右上角 - Logcat）来抓取 log。\n\n注意，要抓取有意义的 log，**你需要在开始 log 后重现问题**。\n\n### 无法进入系统\n\n如果无法进入系统，则需要通过 adb 抓取 log（需要连接电脑）。关于如何使用 adb，请自己搜索。\n\n在开机过程中连接 USB，在 adb 连接后立即执行 `adb logcat > 1.txt`。"
  },
  {
    "path": "storage_redirect/zh-hans/guide/tutorial.md",
    "content": "# 教程\n\n## 启用隔离后会发生什么？\n\n假设存在一个应用 ExampleApp（包名为 `com.example`），它使用了有滥用存储空间行为的 SDK（假设它会创建 `bad_sdk` 文件夹）。那么在授予 ExampleApp 存储权限后，你的存储空间将会是这样的。\n\n```\n/storage/emulated/0\n├───Android\n├───bad_sdk\n├───DCIM\n├───Download\n├───Pictures\n└───...\n```\n\n现在，我们对 ExampleApp 启用隔离，它的存储空间成为其数据文件夹中的一个文件夹。我们称该文件夹为“隔离存储空间”。\n\nExampleApp 会只能使用该文件夹内的文件，由它创建的文件夹也会保存于该文件夹。\n\n```\n/storage/emulated/0\n├───Android/data/com.example  <---- ExampleApp 的数据文件夹\n│   └───sdcard                <---- 隔离存储空间\n│       └───bad_sdk\n└...\n```\n\n另外，由于选用了它的数据文件夹，我们还可以取得这些好处：\n\n* 卸载或清除数据时，这些文件会被一并删除\n* 在系统的应用信息中，这些文件也会被计入存储空间使用量\n\n## 针对新用户的知识\n\n::: details <b>推荐的组织文件的方式</b>\n\n对于照片、图片、下载的文件等用户文件，Android 系统提供了一系列的标准文件夹。\n\n* `Alarms`（闹铃）\n* `Pictures`（图片）\n* `DCIM`（相机）\n* `Documents`（文档）\n* `Download`（下载）\n* `Movies`（影片）\n* `Music`（音乐）\n* `Notifications`（通知音）\n* `Ringtones`（铃声）\n\n以最常用的 `Pictures` 为例，通行的做法是，每个应用各自在其中建立自己的文件夹。比如 Twitter 保存图片至 `Pictures/Twitter`。\n\n我们的建议是，按照上面的方式组织各个应用保存的文件。\n:::\n\n::: details <b>清理/移动已有的文件</b>\n\n由于 `/storage/emulated` 中的文件并没有所有者，我们无法自动地帮助你移动或删除已有的文件。\n\n* 用户文件，如图片\n\n  按照上面推荐的方式进行整理。\n\n* 其他\n\n  对于绝大多数应用，删除先前的文件不会产生问题。但以防万一，我们建议你跟随下面的步骤。\n\n  1. 建立一个临时文件夹并将它们都移入其中。\n  2. 运行所有被隔离的应用。\n  3. 如果有应用因为无法找到之前的文件而不正常工作，你可以借助“查看隔离存储空间”功能了解特定文件夹可能由谁建立并由此移动那些文件夹。\n  4. 所有应用都正常工作后，删除临时文件夹。\n:::\n\n::: details <b>忘掉“清理应用”</b>\n\n一些“清理应用”有清理特定应用建立的文件的功能（那些文件不在数据文件夹中，卸载后不会被删除），这种功能在隔离后因为文件位置变化而无法使用。\n\n但是在隔离后，应用建立的文件都保存于隔离存储空间内（位于其数据文件夹），它们会在卸载后被删除。另外，你可以将隔离存储空间位置设定为缓存文件夹，缓存文件夹会被 Android 系统自动清理。\n\n忘掉“清理应用”吧，它们已不再有用。并且，它们从一开始就不应该存在。\n:::\n\n::: details <b>“备份应用”不会受影响（甚至可以备份更多内容）</b>\n\n“备份应用”只能备份应用的数据文件夹中的文件。\n\n隔离后，应用建立的文件都保存于隔离存储空间内（位于其数据文件夹），因此它们也能被备份了。注意，你可能需要在你的“备份应用”中启用类似于“备份外部数据”的选项。\n:::\n\n::: details <b>使用增强模式</b>\n\n增强模式是一个非常重要的组成部分，[许多问题](./enhanced_mode/)在使用增强模式的情况下才可以解决。\n\n我们建议，当你确认一切正常后就开始尝试增强模式（在应用内可以看到如何使用增强模式）。\n:::\n\n## 应用不正常工作的解决方案\n\n### 应用需要访问特定的文件\n\n现在 ExampleApp 有了发送图片功能。但是因为被隔离，你无法在 ExampleApp 中找到你的图片。\n\n要解决这个问题，我们只需要关注“可访问文件夹”选项中的“共享文件夹”部分。假设我们选择了 `DCIM` 和 `Pictures` 文件夹，ExampleApp 就可以访问这两个文件夹中的文件了。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard        <---- 隔离存储空间\n│       ├───bad_sdk\n│       ├───DCIM      <---- 真实的 DCIM\n│       └───Pictures  <---- 真实的 Pictures\n└...\n```\n\n对于其他情况，你只需要选择对应的文件夹即可。\n\n注意，应用不止可以读取，还可以写入这些文件夹。\n \n#### 不要滥用！\n\n我们只推荐必要的文件夹设为可访问文件夹。如果你将所有的文件夹都设为可访问文件夹，隔离将失去意义。\n\n### 找不到应用保存的文件\n\n现在 ExampleApp 有了下载图片功能，并且你用它下载了 `1.png`。因为被隔离，`1.png` 被保存至隔离存储空间，你无法在相册应用中看到它。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard         <---- 隔离存储空间\n│       ├───bad_sdk\n│       ├───DCIM\n│       ├───images\n│       │   └───1.png\n│       └───Pictures\n└...\n```\n\n要解决这个问题，我们需要建立一个“导出被隔离的文件”规则。\n\n```\n来源：images\n目标：Pictures/ExampleApp\n添加到媒体存储：是\n```\n\n建立规则后，你就可以在相册应用及 `Pictures/ExampleApp` 中看到 `1.png`。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard               <---- 隔离存储空间\n│       ├───images\n│       │   └───1.png\n│       └───...\n├───Pictures\n│   └───ExampleApp\n│       └───1.png\n└...\n```\n\n注意，由于使用了 hard link，因此虽然在两处存在相同的文件，**但是它们只会占用一份存储空间**。有关“导出被隔离的文件”的技术细节，你可以在[这里](./advanced/technical_details_export_isolated_files.md)阅读。\n\n#### 使用在线规则\n\n如果在线规则中已经有了需要的规则，你只需要直接添加它们。只有没有规则的情况或是规则有错误时你才需要自己编写规则。你还可以提交你的规则到在线规则库（通过“上传按钮”）。\n\n#### 不要滥用！\n\n导出的目的是导出**用户文件（由用户发起的保存文件操作，如保存图片、下载文件等操作）**。\n\n如果应用将用户文件保存至私有文件夹（如 `Android/data/<package>/files/example`），此处并不属于隔离存储空间，不适用于导出功能。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   ├───files                <---- 不属于隔离存储空间\n│   └───sdcard               <---- 隔离存储空间\n└...\n```\n\n如果你发现应用将**用户文件**保存于私有文件夹，你应该要求它们的开发者做出改变。\n\n::: details 为什么应该要求应用开发者做出改变？\n\n在 Android 11 中，`Android` 文件夹是真正的私有文件夹。即使有存储权限，应用也只能访问其中属于自己的部分。\n\n```\n/storage/emulated/0\n├───Android\n│   ├───data\n│   │   └───com.example     <---- 属于 com.example\n│   ├───media\n│   │   └───com.example     <---- 属于 com.example\n│   └───obb\n│       └───com.example     <---- 属于 com.example\n└...\n```\n\n将用户文件存放在私有文件夹意味着只有应用自己能看见，**其它任何应用，包括文件管理器，都看不到**。这么做显然是不对的。另外，此处的文件会在卸载或清除数据时被删除，将用户文件保存于此显然不合适。\n\n注意，对于“聊天应用中接收文件”这样的场景，将文件先存放于私有文件夹是合理的。因此，在向应用开发者反馈时，诉求应该是添加“保存到下载”功能（将私有文件夹中的文件移动至 `Download` 文件夹）而不是直接改变文件的位置。\n:::\n\n::: details 另一种“解决方案”\n\n<https://github.com/RikkaApps/SaveCopy>\n:::\n\n### 配合另外的应用使用时出现问题\n\n#### 使用其他应用查看文件（标准方式，即 ACTION_VIEW）\n\n现在 ExampleApp 有了使用其他应用打开图片的功能。很不幸 ExampleApp 直接将文件路径传递给其他应用（这种做法几年前就应该被抛弃！），你会发现其他应用提示“找不到文件”。\n\nExampleApp 自己并不会知道自己被隔离了，它所看到的存储空间是这样的。\n\n```\n/storage/emulated/0    <---- ExampleApp 的视角\n├───bad_sdk\n├───DCIM\n├───images\n│   └───1.png\n└───Pictures\n```\n\n因此，情况是这样的。\n\n> ExampleApp：给你， `example_app/1.png`。\n>\n> 图片查看器：让我们看看试试打开这个文件... 诶~好像并没有这个文件诶！\n\n我们都知道文件实际是位于 `/storage/emulated/0/Android/data/com.example/sdcard/images/1.png`。\n\n::: tip 不再需要对这种情况提供支持\n\n在 Android 11 中 `Android` 文件夹是真正的私有文件夹，这种做法不能正常工作。这么做的应用一定会做出改变。因此，从 v4.4.0 起，对这种情况的支持被移除。\n:::\n\n#### 以非标准方式将文件路径传递给其他被隔离的应用\n\n现在 ExampleApp 添加了向 ExampleSocial 分享图片的功能（ExampleSocial 也是一个被隔离的应用）。很不幸 ExampleSocial 要求使用它的 SDK（这种做法也应该被抛弃！），这意味着又是直接传递文件路径，并且我们无法通过“修复应用间交互”功能改变传递的文件路径。\n\n假设 ExampleSocial 的 SDK 是这样工作：将图片保存至 `tmp` 文件夹，将文件路径传递给 ExampleSocial。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard    <---- ExampleApp 的隔离存储空间\n│       └───tmp/shared_image\n└───Android/data/com.social.example\n│   └───sdcard    <---- ExampleSocial 的隔离存储空间\n│       └───...\n└...\n```\n\n对于 ExampleSocial，`tmp` 文件夹并不存在，因此分享会失败。\n\n要解决这个问题，我们需要建立一个“可访问文件夹”-“其他应用的文件夹”规则。\n\n```\n来源应用：ExampleApp\n目标应用：ExampleSocial\n文件夹：tmp\n```\n\n这样 ExampleSocial 就可以访问来自 ExampleApp 的 `tmp` 文件夹。\n\n#### 如何建立自己的规则？\n\n你需要拿起你的“武器”——“文件监视”。文件监视是增强模式的功能。\n\n继续上面的例子，在 ExampleApp 分享到 ExampleSocial 失败后，你可以在文件监视中看到来自 ExampleApp 和 ExampleSocial 的 `tmp` 文件夹的记录。由此可以知道，你需要建立访问 `tmp` 文件夹的规则。\n\n#### 使用在线规则\n\n如果在线规则中已经有了需要的规则，你只需要直接添加它们。只有没有规则的情况或是规则有错误时你才需要自己编写规则。你还可以提交你的规则到在线规则库（通过“上传按钮”）。\n\n#### 补充包\n\n::: details <b>涉及 Xposed 模块</b>\n\n首先，你需要了解，Xposed 模块不止以模块应用本身运行，它还会在其他应用中运行。\n\n比如一个名为 ExampleXposedModule 的模块有修改 ExampleApp 的功能，那么它也会在 ExampleApp 中运行。如果 ExampleXposedModule 通过建立文件的方式保存设置，ExampleApp 就也需要去读取保存的文件，就会产生与 ExampleApp 分享到 ExampleSocial 同样的情况。\n\n你需要做的还是借助“文件监视”监视了解哪些文件被使用并建立对应的规则。\n\n**但是，最正确的做法应该是要求 Xposed 模块开发者做出更改！**（要求模块开发者使用 `ContentProvider` 共享配置，或是直接将配置保存于目标应用的数据文件夹。）\n:::"
  },
  {
    "path": "storage_redirect/zh-hant/README.md",
    "content": "---\nhome: true\nheroImage: /logo.png\nactionText: 下載\nactionLink: /zh-hant/download.html\nsecondaryActionText: 瞭解更多\nsecondaryActionLink: /zh-hant/guide/\nfeatures:\n- title: 再無濫用\n  details: 為指定的應用程式啟用隔離，它們將只能訪問使用者指定的資料夾。\n- title: 帶回整潔的儲存空間\n  details: 壞應用程式不再可以建立一堆資料夾；根據使用者設定規則將用有用的檔案、媒體等存至規範的資料夾。\n- title: 監視檔案操作\n  details: 監視應用程式的檔案操作，瞭解其使用了哪些檔案。\nfooter: Copyright © 2020 RikkaApps\n---"
  },
  {
    "path": "storage_redirect/zh-hant/changelog.md",
    "content": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- 修復了在 Android 10 以上，沒有寫儲存權限的應用程式沒有顯示「匯出被隔離的檔案 & 重新導系統提供程式」選項的問題\n  \n  在 Android 10 以上，Android 系統允許符合條件的應用程式（**即使它沒有請求任何權限**）寫入標準資料夾（符合條件的應用程式是指目標 API 是 30 或以上，或者目標 API 是 29 且適配了 Scoped Storage 的應用程式）。此選項對此類應用程式是有意義的。\n\n## 8.4.2 (2023-03-22)\n\n- 修復自從 8.4.0 版本起，如果「暗色主題」沒有被設為「跟隨系統」時應用程式無法使用的問題\n\n## 8.4.1 (2023-03-17)\n\n- 修復上個版本中在未使用增強模式的情況下進入應用程式列表時應用程式會崩潰的問題\n\n## 8.4.0 (2023-03-12)\n\n- 修復首次啟動核心服務時會強行停止有匯出規則的應用程式（不論規則是否啟用）的問題\n- 【僅限 Android 10 及之前的版本】檔案監視功能不再強制要求安裝 Shamiko（但請注意，隱藏解決方案仍是必要的，因此檔案監視的開關在更新後會被關閉）\n- 修復只請求了 Android 13 新增的權限的應用程式被判定為未請求權限的問題（上個版本並未正確修復）\n- 針對中日韓語言使用者，如果系統沒有提供 Medium（500）字重的字型，則會使用模擬實現\n\n## 8.3.0 (2023-01-03)\n\n- 修復了 Android 11 以上未請求權限的應用程式被跳過不處理的問題（在 Android 11 以上，無任何權限的應用程式也可以在標準資料夾中寫入檔案和資料夾）\n- 修復只請求了 Android 13 新增的權限的應用程式被判定為未請求權限的問題\n\n## 8.2.2 (2022-12-05)\n\n- 在請求線上規則前需要使用者同意\n\n## 8.2.1 (2022-11-22)\n\n- 更好的 Android 13 支援\n\n## 8.1.0 (2022-10-15)\n\n- 保證帶有 `Shared user ID` 的應用程式會使用固定的隔離儲存空間\n- 修復在使用 Zygisk 版本的增強模組時進行了一些不必要的檢查的問題\n- 提前修復一個會導致受限模式在下一個 Android 版本無法使用的問題\n\n## 8.0.0 (2022-08-21)\n\n- 全新的檔案監視實現\n- 在 Android 10 及更高版本停用實際不需要的「修復 rename」\n- 修復重新安裝解除安裝但保留資料的應用程序不顯示的問題\n\n新舊檔案監視的區別：\n\n舊：\n- 需要進入每個行程（可能會被檢測，尤其是 Zygisk 版本）\n- 不能記錄直接 syscall 的和延後載入的原生庫進行的操作\n\n新：\n- 無需進入所有行程\n- 可以記錄原先不能記錄的操作，但是不能記錄被隔離的應用程序進行的操作\n- 需要 Android 11 及以上版本（如果裝置執行 Android 10 或更舊版本則仍會使用舊版本）\n\n## 7.5.3 (2022-06-14)\n\n- 修復 v7.5.2 在 Android 10 及以下壞掉\n\n## 7.5.2 (2022-06-14)\n\n- 修復「處理系統提供程式」導致某些應用程式無法訪問已設定為可訪問的檔案的問題\n\n## 7.5.1 (2022-06-09)\n\n- 修復在 Android 13 Beta 3 上不工作\n\n## 7.5.0 (2022-05-20)\n\n- 增強模組 v27：在沒有 sdcardfs 的裝置上恢復「訪問其他應用的資料夾」功能\n- 一些 UI 調整\n\n## 7.3.4 (2022-05-06)\n\n- 重做備份和恢復功能（舊的備份仍然支援，但是強烈推薦使用新版本應用程式建立新的備份）\n- 試修復損壞的資料庫檔案導致檔案監視功能壞掉\n- 切換到 Material Design 3（Material You）\n\n## 7.1.0 (2022-02-22)\n\n- 支持 Android 13 DP1（但是，根據經驗，DP1 是非常早期的版本，應用程序很可能會因為 DP2 的改動再次無法工作）\n- 增強模式 26.1.0：修復文件監視功能導致下載管理器在部分 OnePlus（OPPO）設備上壞掉的問題\n\n## 7.0.0 (2022-01-29)\n\n- 增強模式支援 Zygisk\n- 修復不能列出僅在非主使用者中安裝的應用程式的問題\n\n## 6.4.0 (2021-12-13)\n\n- 修復在 Android 11 以上，為帶有 `Shared user ID` 的應用程式建立匯出規則時，無法選擇來源資料夾的問題（沒有顯示任何資料夾）\n- 一些 UI 調整\n\n## 6.3.0 (2021-11-14)\n\n- 更正有關 Android 11 上應用程式無需權限即可寫入檔案到標準資料夾的說明\n- 一些 UI 問題修復\n- 提升目標 SDK 版本到 31\n\n## 6.2.0 (2021-10-14)\n\n- 顯著提高檔案監視的效能，特別是對於有大量記錄的使用者\n- 修復當給檔案監視設定了過濾時常常無法展示所有記錄的問題\n- 修復檔案監視可能不能正確展示來自「媒體儲存裝置」的記錄的問題\n- 更正有關 Android 11 上目標 API 為 30 以上的應用程式無需權限即可寫入檔案到標準資料夾的說明\n- \n## 6.1.10 (2021-09-16)\n\n- 在 Android 11 以上，允許為媒體儲存裝置等應用程式將 `Android` 資料夾中的資料夾設為可訪問資料夾\n\n## 6.1.9 (2021-09-03)\n\n- 修復在沒有 `sdcardfs` 的裝置上，應用程式可能無法訪問被「匯出被隔離的檔案」規則所使用的資料夾的問題\n- 修復一個 UI 問題\n\n## 6.1.8 (2021-08-29)\n\n- 當檔案監視的資料庫損壞時重新建立\n- 修復一個會導致核心服務崩潰的內部問題\n\n## 6.1.5 (2021-08-12)\n\n- 正確處理系統服務重新啟動\n\n## 6.1.4 (2021-07-14)\n\n- 修復自從 6.1.0 版本起可能不能正確地隔離帶有 `Shared user ID` 的應用程式的問題\n- 修復不能在不同的使用者新增相同的「允許訪問來自其他應用程式的資料夾」規則的問題\n- 修復可訪問資料夾選擇器不能顯示不存在但已選擇的資料夾的問題\n\n## 6.1.0 (2021-06-30)\n\n- 允許隔離只有讀儲存權限的應用程式\n- 在 Android 10+，在增強模式下，允許隔離無儲存權限的應用程式\n  \n  沒有儲存權限的應用可以透過媒體儲存將媒體（圖片、影片、音樂）檔案寫入標準資料夾。有些應用程式透過生成假媒體檔案來持久化其資料。\n\n- 修復增強模組有時顯示為沒有安裝的問題\n- 修復在 x86 裝置開啟就崩潰\n- 從應用列表隱藏部分應用程式（無元件的程式、無程式碼的程式、overlay 程式，此類程式無法執行，隔離它們沒有意義）\n\n## 6.0.2 (2021-06-27)\n\n- 增強模組 v25：\n  - 應用程式不再可以透過媒體儲存裝置使用非可訪問資料夾（舊版本無法處理 Android 10 開始的新方法）\n  - 應用程式使用媒體儲存裝置的事件可被檔案監視記錄\n  - 從零開始重做與媒體儲存裝置有關的部分，相較以前有更好的效能及相容性\n- 改進檔案監視 UI\n- 修復從 Android 12 Beta 1 開始，相簿預覽會讓核心服務崩潰\n- 由於模組 v25 的巨大變化，舊版本的增強模組不再支援\n- 移除一些從超級舊的版本遷移設定的程式碼\n- 修復在 x86 裝置開啟就崩潰\n\n## 5.4.5 (2021-05-21)\n\n- 受限模式（不安裝增強模組）在 Android 12 Beta 1 上工作\n- 為檔案監視新增「排除私有檔案」選項\n\n## 5.4.3 (2021-05-06)\n\n- 修了在可訪問資料夾模板需要較長時間才能載入的問題\n\n## 5.4.1 (2021-05-04)\n\n- 阻止 💩 MIUI 的「強制深色模式」弄壞自己的深色主題<sup>**〔1〕**</sup>\n\n<sub><b>〔1〕</b>MIUI 有自己的「強制深色模式」，但是似乎即使應用程式正確地提供了深色主題，它也會繼續起作用，從而把顏色改亂。</sub>\n\n## 5.4.0 (2021-05-03)\n\n- 嘗試解決可能存在的不能隔離 Android 11 及以上版本的媒體儲存裝置的問題（在 MIUI 上，隔離它可能是必要的）\n- 增加了多個針對 Android 11 及以上版本系統的防呆設定\n- 記錄從始至終執行隔離的次數\n\n## 5.3.5 (2021-04-28)\n\n- 嘗試修復一個可能導致核心服務崩潰的問題\n- 從應用列表隱藏部分應用程式（無元件的程式、無程式碼的程式、overlay 程式，此類程式無法執行，隔離它們沒有意義）\n\n## 5.3.4 (2021-04-27)\n\n- 修復一個只在極少的裝置上出現的「修復程序間互動」功能導致被隔離的應用程序卡死的問題\n\n## 5.3.1 (2021-03-27)\n\n- 採用[自己編譯的 libcxx](https://github.com/RikkaW/libcxx-prefab)來減少檔案大小（減少了約 300KB）\n- 增強模組升級到 Riru 25\n- 適應一個 Android 12 的改變\n- 當增強模式沒有正常工作時給予提示\n- 處理了一些 Android 11 及以上使用者主動關閉了 fuse 後的問題\n\n## 5.2.0 (2021-01-27)\n\n- 修了在 Android 11 上，對於非主使用者，所有需要列出檔案的功能均無法正常使用的問題\n\n## 5.1.0 (2021-01-19)\n\n- 支援通過 Sui（https://github.com/RikkaApps/Sui）啟動（當然由於這個應用程式複雜度過高，真的就只是啟動而已）\n- 檔案監視現在顯示非主使用者的記錄\n\n## 5.0.2 (2020-12-20)\n\n- 修了一個可能導致有 `sharedUserId` 的應用程式（應用程式內稱為「程式組」）無法被隔離的問題\n- 當「阻止系統重新掛載」可用時不再自動允許 `OP_REQUEST_INSTALL_PACKAGES`（以前這麼做的原因是 `OP_REQUEST_INSTALL_PACKAGES` 改變會觸發系統重新掛載導致隔離失效）\n\n## 5.0.1 (2020-12-15)\n\n- 修了在 Android 11 上新新增的「匯出被隔離的資料夾」規則不會立刻生效的問題\n\n## 5.0.0 (2020-11-23)\n\n- 支援出廠 Android 11 的移除了 `sdcardfs` 的裝置（如 Pixel 5，Pixel 4a 5G 等）\n- 在 Android 11，「匯出被隔離的檔案」使用 `mount` 而不是 `hard link` 實現（因為媒體儲存裝置無權訪問連結檔案）\n- 所有涉及 `untrusted_app` 域的跨程式通訊均已使用 binder（許多部分被完全重寫）\n- 幾乎去除所有表明裝置已 root 的痕跡\n- 使用 `/data/adb/storage-isolation` 資料夾，如果沒有問題你可以刪除 `/data/misc/storage_redirect`\n- 講出所有的變化很難 😶\n\n## 4.5.3 (2020-08-20)\n\n- 改變核心部分做法，應該不再會有先前版本的「適應 Android 11 的改變」帶來的問題\n- 適應 Android 11 beta 3 的變化\n\n## 4.5.2 (2020-06-19)\n\n- 不讓放任一個奇怪的錯誤<sup>**〔1〕**</sup>致使整個程式崩潰\n\n<sub><b>〔1〕</b>An error related to Retrofit + Kotlin coroutines, stacktrace is empty</sub>\n\n## 4.5.0 (2020-06-16)\n\n- 修復在 Android 11 上隔離早於使用者解鎖啟動的應用程式會導致嚴重的問題\n- 當「增強模式」-「禁止系統重新掛載」啟用時，隔離的應用程式的儲存權限不再不可改變<sup>**〔1〕**</sup>\n- 增強模式：「禁止系統重新掛載」在 Android 11 上工作\n- 增強模式：「修復程式間互動」在 Android 11 上工作\n- 增強模式：移除「修復程式間互動」的 toast 提示（對於檢查的使用場景，請檢查 tag 為 \"SRHook\" 的 log）\n- 增強模式 v22.6：修復應用程式級別的「修復程式間互動」開關不起作用\n- 可自訂「匯出被隔離的檔案」規則標題\n- 改善「應用程式設定」頁面效能\n- 「相簿預覽」在 Android 11 上工作\n- 當應用程式開機啟動，不要殺死由增強服務啟動的行程\n- 提升目標 API 版本到 30\n- 改變了圖示\n\n<sub><b>〔1〕</b>根據使用者報告，這在 MIUI 這樣的 💩 系統上可能會出現問題。</sub>\n\n> 根據使用者報告及調查，「修復程式間互動」在一些高度修改的系統（至少包括 💩 一加）上不工作。我們將會在未來切換到一個完全不同的方案。\n\n## 4.4.1 (2020-05-01)\n\n- 修復「檔案監視」頁面卡頓\n- 修復「可訪問資料夾」-「其他程式的檔案」顯示錯誤\n\n## 4.4.0 (2020-04-29)\n\n- 修復程式間互動：移除 \"startActivity hook\"<sup>**〔1〕**</sup><sup>**〔2〕**</sup>\n- 修復在一些情況下改變「預設隔離儲存空間位置」會一直等待\n- 正確地實現「向上」（ActionBar 中的箭頭）<sup>**〔3〕**</sup><sup>**〔4〕**</sup>（但很悲傷，甚至系統程式也沒有做對 😰）\n- 為所有顯示於系統欄下的列表修復 edge effect（幾乎所有程式都沒做對這個 😋）\n- 因為相簿預覽在 Android R 上壞掉所以暫時隱藏\n\n<sub><b>〔1〕</b>這會產生問題。</sub>\n<br><sub><b>〔2〕</b>在 Android 10+，暴露 `file` uri 會導致崩潰，垃圾程式應該已經做出改變。我們不再需要去「幫助」它們。</sub>\n<br><sub><b>〔3〕</b>根據<del>上古</del>規範，「返回」應導航至前一螢幕但「向上」應導航至邏輯上的上一級。例如，從 B 進入 A 的一個深層頁面，「返回」返回到 B 但是「向上」去往 A 的上一層。（這也需要 B 做對）</sub>\n<br><sub><b>〔4〕</b>在 Android R 開發者預覽版本中，Google 弄壞了這個「沒人用的東西」，因此「向上」仍然像「返回」一樣運作。</sub>\n\n## 4.3.1 (2020-04-05)\n\n- 新增一個簡單一些的提交規則方式\n- 修了不能為非主使用者的應用程式新增「可訪問資料夾」-「其他應用程式的資料夾」規則的問題\n- 修了一些 UI bug\n\n## 4.2.3 (2020-03-24)\n\n- 解決與以 `setApplicationHiddenSettingAsUser` 為原理的凍結類應用程式一起使用時出現的問題\n\n## 4.2.2 (2020-03-22)\n\n- 修復程式設定中線上規則早於可訪問資料夾載入導致網路較差時體驗糟糕的問題\n\n## 4.2.1 (2020-03-21)\n\n- 改變「新程式通知」及「匯出被隔離的檔案」規則的通知的實現，這可以繞過 💩 MIUI 的系統 bug <sup>**〔1〕**</sup>以及另一個祖傳小問題 <sup>**〔2〕**</sup>\n- 增強模組版本現在線上獲取\n- 「可訪問資料夾模板」的應用程式列表現在正確支援多使用者\n- 更多防呆設計\n\n<sub>**〔1〕** 在不明確的情況下，MIUI 會在 system_server 中對 startActivity 傳入的 Intent 中的 Bundle 進行反序列化。如果 Bundle 中包含非系統的 Parcelable，則反序列化會失敗且無法復原，應用程式只會收到空白的 Bundle。</sub>\n<br><sub>**〔2〕** 如果資料結構發生變化，且安裝新版本應用程式後尚未更新核心服務，則出現通知時應用程式會崩潰。</sub>\n\n## 4.2.0 (2020-03-14)\n\n- 為啟動較早的系統程式啟用隔離不再會有問題（但是，以防萬一，你仍需要[做好準備](./guide/enhanced_mode/install.html#無法進入系統（通常是由於隔離了系統元件）)）\n- 完全修好恢復備份\n- 修復特定的情況下程式失去響應（白屏）\n\n## 4.1.7 (2020-03-10)\n\n- 「匯出被隔離的檔案」規則現在參與「修復程式間互動」功能的計算（需要重新啟動受影響的應用程式才可以讓改動生效）\n- 修復修改可訪問資料夾模板不會立刻生效的問題\n- 修復由於系統更新導致的多使用者支援壞掉\n- 為隔離重要系統程式及程式組的流程加入防呆設計\n\n## 4.1.6 (2020-03-06)\n\n- 可以使用內建 logcat 來取得開機 log（不再於啟動時清除 log & 修復 UI 不響應）\n- 已解除安裝應用程式的「匯出被隔離的檔案」規則不再參與衝突檢查\n- 修復一旦使用者進入其他頁面，「檔案監視」就不再重新整理的問題\n- 修復極少數的「檔案監視」記錄不顯示的問題\n- 修復罕見的被隔離的應用程式不啟動問題\n\n## 4.1.5 (2020-03-04)\n\n- 完全解決上個版本所解決的問題\n\n## 4.1.4 (2020-03-03)\n\n- 修复「禁止系統重新掛載」功能失效<sup>**〔1〕**</sup>\n\n<sub>**〔1〕** 此功能應該只有 MIUI 11（或許只有中國大陸版本？）需要</sub>\n\n## 4.1.3 (2020-03-01)\n\n- 再次調整啟動核心服務的一部分的時機（在 MIUI 或許還有其他的奇奇怪怪的系統上，啟動太早或太晚都會有問題，太難了（\n- 修復一個有關恢復備份的問題\n\n## 4.1.2 (2020-02-29)\n\n- 修復由 4.0.0 引入的部分人會出現購買資訊丟失的問題\n- 新增「禁用匯出被隔離的檔案的通知」選項，因為在使用增強模式的「修復應用程式間互動」後通知沒有意義（該選項僅對新使用者預設啟用）\n- 修復來自程式組的「匯出被隔離的檔案」規則在新增/更新/刪除時可能出現問題\n- 修復恢復備份時部分應用程式無法被恢復的問題\n- 修復數個有關「修復程式間互動」的問題\n\n## 4.1.0 (2020-2-28)\n\n- 為避免問題，所有非普通應用程式（uid < 10000）將在本次升級時停用隔離（根據回報，隔離 uid 1000 的應用程式可能會在 MIUI, OnePlus Oxygen OS 等重度修改系統上產生問題）\n- 修復上個版本檔案監視不工作\n- 修復上個版本可能的配置丟失\n\n## 4.0.0 (2020-2-28)\n\n- 修改程式名稱為「儲存空間隔離」，因為「重新導向」十分容易讓人誤以為是舊時代的「重新導向到 SD 卡」\n- 正確支援 Android 系統的 `sharedUserId` 機制（幾乎所有部分都需要改動，上次更新到現在大部分時間都花費於此）\n- 核心服務在「非正常重新啟動」後仍可正常運作\n- 修復在 Android 10 上關閉隔離後儲存權限顯示為允許但實際為不允許且無法改為允許的問題\n- 不再將 AOSP 程式視為已認證\n- 現在如果有人沒事把 \"Android\" 資料夾重新命名為 \"android\" 甚至改來改去，「匯出被隔離的檔案」功能也能正常執行（到底是什麼人才會這麼無聊）\n- 增強模式 v22：更早啟動核心服務中的一部分，這可以解決為非常早啟動的程式啟用隔離可能會導致無法開機的問題（對，這又是僅限 💩 MIUI 的問題）\n- 增強模式及 Riru 版本號永遠不再顯示為未知\n- 若重新安裝曾經啟用隔離的程式，原先的設定會被正確地恢復（是否啟用隔離的開關仍需要手動開啟）\n\n## 3.2.2 (2019-12-22)\n\n- 修復一個有關恢復備份的問題\n\n## 3.2.0 (2019-12-18)\n\n- 修復使用了增強模式時為非常早啟動的應用程式啟用隔離可能產生問題（對，這又是「為了繞過 💩 MIUI 的問題做出的改動」產生的問題）\n- 幾乎改了每一處的 UI 改進\n\n## 3.1.5 (2019-12-06)\n\n- 退回 3.1.4 中的一些改動，因為在另外一部分人上又有問題（\n\n## 3.1.4 (2019-12-05)\n\n- 修復一個啟動過程的問題\n\n## 3.1.3 (2019-11-24)\n\n- 嘗試規避「禁止系統重新掛載」功能可能造成「重新啟動」的問題（注意，新的改變需要重新啟動後才會生效）\n- 匯出被隔離的檔案（同步資料夾）功能會先刪除目標資料夾中同名的檔案，這是為了嘗試避免一些應用程式進行數個重新命名/移動等操作後「錯誤的」檔案被匯出的問題\n- 增加本地規則預置字串以供關閉線上規則或網路不可用時使用\n\n## 3.1.0 (2019-11-23)\n\n- 增強模式：「修復程式間互動」現在可以處理對「下載管理器」的請求\n- 修復在 Android 10 上儲存權限可能沒有正確授予的問題\n- 其他小 BUG 修復與 UI 改進\n\n## 3.0.0 (2019-11-21)\n\n- 重新設計多處 UI，降低理解難度\n- 重構多處 UI 相關部分，增加穩定性與流暢性\n- 增強模式 v21：增加「禁止系統重新掛載」功能以避免系統觸發的重新掛載導致隔離失效（在 Android 9 以上可用）<sup>**〔1〕**</sup>\n- 增強模式：加回「修復程序間交互」中的修改傳遞的文件路徑功能，但暫時只處理 `ACTION_VIEW`<sup>**〔2〕**</sup>，且不再經由儲存重新導向中轉<sup>**〔3〕**</sup>\n- 重新設計在線規則，更加靈活\n\n<sub>**〔1〕** 此功能應該只有 MIUI 11 需要</sub>\n<br><sub>**〔2〕** 觸發反序列化 `extras` 很危險</sub>\n<br><sub>**〔3〕** 即使我們什麼也不做，原始行爲在 Android 10 上已經會造成崩潰，我們沒有必要越庖代俎爲劣質應用「修復問題」</sub>\n\n## 2.1.5 (2019-10-30)\n\n- 修復一些 UI BUG\n\n## 2.1.4 (2019-10-29)\n\n- 改進一些核心部分的實現\n- 修復一些 UI BUG\n\n## 2.1.3 (2019-10-23)\n\n- 繞過在 OnePlus 的 Android 10 上使用自動暗色主題會崩潰的問題（這個問題由 OnePlus 的引起）\n\n## 2.1.1 (2019-10-23)\n\n- 修復如果核心程序啟動晚於啟用的應用程式則該應用程式可能無法啟動的問題\n\n## 2.1.0 (2019-10-22)\n\n- 簡化允許訪問來自其他程式的檔案流程，現在只要是由其他程式建立的檔案都可以在「屬於其他程式的資料夾」中選擇\n- 在每次程式啟動時檢查並授予權限，這可能解決由 MIUI 11 隨機篡改權限造成的問題\n- 繞過在 Meizu 裝置上使用內建 su 時核心工作程序會被殺死的問題\n- 臨時移除「修復程式間互動」中的修改傳遞的檔案路徑功能，因為這個功能在使用 plug-in 或 hot fix 技術的程式（常見於來自中國大陸地區的程式）中會產生問題，且目前主流程式應該都已使用 Content Provider 與其他程式共享檔案，移除此功能應該影響不大\n- 其他 BUG 修復與大量 UI 改進\n\n## 2.0.1 (2019-09-27)\n\n- 修復「共享資料夾」規則實際沒有生效\n\n## 2.0.0 (2019-09-27)\n\n- 對「共享資料夾」及「同步資料夾」規則進行問題檢查（有問題的規則會被刪除有問題的部分或禁用），在下個版本會針對這個這個問題提供更加詳細的提示及教程\n- 修復數個有關「同步資料夾」規則的問題\n- 修復獨立「修復程式間互動」開關壞掉\n- 增強模式 v20.1：修復「修復程式間互動」功能在 OnePlus Android 10（可能還有其他）上的問題\n- 大量 UI 改進\n\n## 1.9.1 (2019-09-09)\n\n- 修復「修復程式間互動」可能沒有工作的問題\n- 增加半透明狀態列及導航欄選項\n- 修復數個 UI bug\n\n## 1.9.0 (2019-09-08)\n\n- 增強模式 v20.0：修復使用 [Adoptable Storage](https://source.android.com/devices/storage/adoptable) 時安裝在外接儲存卡的應用無效的問題\n- 增強模式 v20.0：更改「修復程式間互動」功能的實現方法，不再會被「Xposed Taichi」破壞，同時也可能會解決一些其他的問題\n- 增強模式 v20.0：「修復程式間互動」可單獨為每個程式開關\n- 修復備份功能不能還原部分配置的問題\n- 在 Android Q 上自動允許 `OP_REQUEST_INSTALL_PACKAGES`（因為其發生變化時會觸發系統重新掛載）\n\n## 1.8.3 (2019-08-30)\n\n- 修復一些 UI bug\n- 修復「基礎模式」下的一個重大問題\n\n## 1.8.2 (2019-08-27)\n\n- 處理特殊系統程式（appId < 10000 或 appId > 19999, appId = uid % 100000）\n- 不為特殊系統程式鎖定權限\n- 其他 bug 修復和 UI 改進\n\n## 1.8.1 (2019-08-26)\n\n- 改進選擇「可訪問資料夾」流程\n- 可直接為「可訪問資料夾模板」選擇使用的應用\n- 修復在 Android Q 上啟動服務時對已啟動的應用程式的重新導向會失效問題\n- 修復長時間停留在主介面 CPU 佔用會越來越高問題\n- 修復使用 API（暫未公開）的應用程式崩潰的問題\n- 其他 bug 修復和 UI 改進\n\n## 1.8.0 (2019-08-17)\n\n- 選擇「可訪問資料夾」時可同時選擇多個模板及自訂\n- 增加「資料夾分析」功能，獲知隔離儲存空間中資料夾大小\n- 可訪問資料夾中選擇的資料夾不存在時會自動建立\n- 一些些 UI 改進和 bug 修正\n\n## 1.7.5 (2019-08-06)\n\n- 修復「同步資料夾」功能壞掉\n\n## 1.7.4 (2019-08-05)\n\n- 在 Android Q 上使用 `FLAG_PERMISSION_SYSTEM_FIXED` 來固定權限\n- 為 Huawei 裝置提供解決方法，[詳見此處](./guide/compatibility/huawei.html)\n- 修復「同步資料夾」功能沒有嘗試處理「從目標資料夾移走檔案」事件\n- 改進英語翻譯\n- 其他小改動\n\n## 1.7.2\n\n- Fix \"Code 5\"\n- Other bug fix\n\n## 1.7.0\n\n* Basic mode now works on Android Q beta 4\n* Correctly handle hide/unhide (commonly used by \"Freeze\" apps)\n* Change target SDK version to 29 (Android Q)\n\n## 1.6.12\n\n* Fix app list not refreshed after restoring backup\n* Use a more reliable method to monitor app install/uninstall\n* Notify user if no browser app available when opening help documents\n* Fix a bug related \"Fix app interaction issues\" \n* Other bug fix\n* UI improve\n\n## 1.6.9\n\n* Fix Enhanced mode not work for apps starts early than core service\n\n## 1.6.8\n\n* Fix apps not starting on new users\n* Support Android Q beta 3 (including Enhanced mode)\n* Remove the ability to choose \"Android/sandbox\" as isolated storage path since from Q beta 3 the system sandbox is only used for apps which declared support the sandbox\n\n## 1.6.7\n\n* Clear config (app info - storage - clear/manage data) feature dose clear all configs now\n* Filter duplicates or incorrect mounts in the final stage to avoid problems from user misuse\n* Fix \"Fix app interaction issues\" may incorrectly handle files in `Android/data(media, obb)/package`\n\n## 1.6.6\n\n* Fix app interaction issues (Enhanced mode): Grant content uri permission\n* UI improve\n\n## 1.6.4\n\n* Fix app interaction issues (Enhanced mode): Always convert file uri to content uri on Android Q\n* Enhanced mode: remove disable file uri expose check since it is meaningless\n* Allow choosing \"Android/sandbox\" as isolated storage path on Android Q\n* Other bug fix\n\n## 1.6.3\n\n* Enhanced mode works on Android Q\n* Enhanced mode: force disable file uri expose check for Android Q system ui\n* Improve App settings UI\n* Try fix config lost (should be extremely rare), add \"Debug info\" for users to investigate this problem\n* Fix storage permission can't be revoked if redirect is already disabled\n\n## 1.6.2\n\n* Add \"View gallery as this app\", you can learn which photos the app can access\n* Bug fix & UI improve\n\n## 1.6.0\n\n* Works on Android Q DP2 (enhanced mode not supported yet)\n* Change behavior, mount Android/media/xxx & Android/obb/xxx by default\n* Huge UI improve\n* Fix \"Fix app interaction issues\" never worked on some devices\n\n## 1.5.7\n\n* Continue fixing bugs caused by \"Fix app interaction issues\"\n* Continue renaming options\n\n## 1.5.6\n\n* Fix new storage permission method breaks on MIUI\n* Fix \"Fix app interaction issues\" feature causes app breaks on some situations (if extra contains Parcelables from non-BootClassloader)\n\n## 1.5.5\n\n* (Android 6.0-7.1) Fix \"Fix app interaction issues\" feature cause app crash or all media not shown\n* Continue renaming options, app name would even change in the future\n* Reduce extra app launching time\n  \n  On my OnePlus 3T, average extra time reduced from 0.3s to 0.16s\n  \n  * Enforce storage permission with API (do not need check everytime), save average 0.04s\n  * (only on 7.0+) Limit \"File monitor\" hook target, save average 0.1s\n  \n## 1.5.3\n\n* Enhancement module v19, please upgrade as soon as possible\n\n  * \"Fix app interaction issues\": try bypassing the problem that apps use \"Tencent app protect\" (腾讯乐固) will crash (v19)\n  * \"Fix app interaction issues\": fix some media are filtered incorrectly (app 1.5.1, v19)\n  * \"Fix app interaction issues\": fix app may crash when \"Access files from other redirected app\" rules enabled (v18.1)\n\n## 1.5.0\n\n* New Enhancement module v18\n  \n  Rewrite \"Fix file uri\" feature, upgrade to \"Fix app interaction issues\" feature \n  \n* UI change\n* Rename some options, reduce the understanding difficulty\n\n## 1.4.9\n\n* Fix \"Synced folders\" feature is broken in 1.4.8\n\n## 1.4.8\n\n* Fix regex check of \"Synced folders\" rules is not proceed when enabling the rule\n* Revoke app storage permission automatically when disabling redirect\n* Other bug fix\n\n## 1.4.7\n\n* Fix Enhancement module installation error reporting\n* Fix Google purchase issue reporting\n* Bad connection with Google Play will not freeze the whole app forever (but 5s)\n* Fix \"Fix file uri\" feature in Enhancement module may sometimes crash redirected app \n* Correctly report some type of error on start\n* Other bug fix\n\n## 1.4.6\n\n* Improve Enhancement module installation detection and provide solution\n* Improve \"Invalid license\" page\n* Bug fix\n\n## 1.4.4\n\n* Bug fix\n\n## 1.4.2\n\n* Report Enhancement module not correctly installed\n* Improve home\n\n## 1.4.1\n\n* Fix license check\n\n## 1.4.0\n\n* New home page\n* Rename/re-layout options, reduce the understanding difficulty\n\n  * \"Non-redirect folders\" -> \"Read/writable folders in real storage\"\n  * \"Link\" -> \"Synced folders\"\n\n* New Enhancement module v17, not more \"I can't open redirected apps\"\n* Fix tons of bugs\n\n## 1.3.3\n\n* Fix bug of Enhance module v16\n\n## 1.3.2\n\n* Enhance module v16, fix a problem related to passing file uri\n  (Example: can't open a received file in WeChat)\n* New native starter (for some strange devices without executables like `chmod`, `rm`)\n* Fix bugs related to link feature\n* Other minor bug fix\n\n## 1.2.2\n\n* Fix mask template for link rule editor\n* Add \"Link function only\" filter in \"Logcat\"\n* Minor bug fix\n\n## 1.2.1\n\n* Add \"Kill Media Storage on start\" option\n  (on some devices, Media Storage can use all CPU on boot, kill it can solve the problem\n  (it can be started by other apps later))\n* Add mask template for link rule editor\n* Try to detect no log\n* Minor bug fix\n\n## 1.2.0\n\n* Add \"Shared folder\" to solve the problem that files created by\n  a redirected app can't be used by another redirected app\n* Refreshed detail UI\n* Enhanced \"Redirect storage viewer\"\n* Enhanced filter for \"File monitor\"\n* Enhance module v15, fix the problem that redirect apps can't move files between specific folders\n  (Example: bilibili can't save gif)\n* Minor bug fix\n\n## 1.1.4\n\n* Enhanced \"Non-redirect folders\" template mechanism\n* Show conflicting rule info\n\n## 1.1.2\n\n* Simplified detail UI\n* Try to support other su, confirmed support MagiskSU, SuperSU, LineageOS addonsu now\n* Fix the problem that server may send wrong progress to client\n  when change \"Default redirect target\"\n* Delete redirected app config after that app uninstall\n* Improve app list performance\n* Improve chooser dialogs\n* Improve File monitor\n* Add non standard behavior check (use file monitor data)\n\n## 1.0.2\n\n* Fix UI not refreshed when add link rules online\n* Fix the problem that \"You have already own this item\" happens on some Google Play users\n\n## 1.0.0\n\n* Add \"Non-redirect folders\" template, you can create different templates\n  for different situations and apply them quickly\n* Enhance module v14, changes behavior, may avoid some special problems on\n  some devices\n* Bug fix\n\n## 1.0.0-rc9\n\n* New logcat UI\n* Fix unpaid state check\n* Migrate to AndroidX library\n\n## 1.0.0-rc8\n\n* Improve user experience\n* Minor bug fix\n\n## 1.0.0-rc7\n\n* Fix \"Launch\" button not work\n\n## 1.0.0-rc6\n\n* Improve user experience\n* Bug fix\n\n## 1.0.0-rc5\n\n* Add White / Light blue theme\n* Try to hide overlay packages\n* Fix can't open installer in file browser\n* Fix some link rules can't be added\n* Bug fix\n\n## 1.0.0-rc4\n\n* Add manually set /data/media path for some special devices\n* Bug fix\n\n## 1.0.0-rc3\n\n* Fix Android/data can be chosen as a \"Non-redirect folder\"\n* Bug fix\n\n## 1.0.0-rc1\n\n* New theme\n* New detail UI\n* Add local link rule\n* Multi-user support\n* Fix backup bug, but backup files created before 1.0.0-rc1 is unavailable\n* Try to detect real internal storage path\n\n## 0.18.2-beta\n\n* Fix bug\n\n## 0.18.0-beta\n\n* \"Non-redirect folder\" (old \"Standard folder\") is now customizable like \"Redirect target folder\"\n* Add Backup & restore\n* Works with LineageOS's addonsu, but some non-core feature may break, still recommended to use Magisk\n* Fix crash when change filter in the main list\n* Fix redirected files may not be moved when change redirect target folder in some cases\n\n## 0.17.4-beta\n\n* Fix link feature not on some (old? special?) devices\n* Try to fix owner of linked files' is 0 on older Android system (chown ourselves)\n\n## 0.17.3-beta\n\n* Fix a critical bug that if an app's redirect target is set different\n  from the default, it will not able to access files in public folders\n* Fix others bugs in 0.17.x\n\n## 0.17.1-beta\n\n* Add set redirect target folder (globally and pre-app)\n* Add app installed notification\n* Also kill by uid when force stop package (for OnePlus stock ROM)\n* Improved \"Share helper\"\n* Bug fix\n\n## 0.16.4-beta\n\n* Add file stat for Redirect storage viewer\n* Fix the problem that anyone is displayed as purchased\n* Auto clean old server files\n* Try to \"fix\" IAP problem \"You have already own this item\"\n* Link files from target to source when enabling link rules\n\n## 0.16.2-beta\n\n* Enhanced File monitor: load more & filter by path / app\n* Force grant storage permission for redirected apps\n* Try to fix bug of link function (when create and delete files in a very short time)\n* Create \".nomedia\" file in Android/data/xxx automatically\n* Add shortcut for File monitor (Android 7.1+)\n* Fix crash when open help if no browser app installed\n* Add more tips\n* Fix bugs in 0.16.1 / 0.16.2\n\n## 0.15.8-beta\n\n* Files downloaded by redirected apps can be managed in Android's Files (DocumentUI) app\n* Fix log parse (only some special ROM)\n* Add \"Show disabled apps\" filter\n* New app list style\n* In-app logcat now catches logs from more sources\n\n## 0.15.4-beta\n\n* Fix reboot when new file created in folders monitored by link function (only on 8.0)\n* Fix a bug of file monitoring function of the link function\n\n## 0.15.2-beta\n\n* Try to fix crash on boot (only some users)\n* Fix log parse (only some special ROM)\n* Auto shrink file monitor database file\n\n## 0.15.1-beta\n\n* Enhance module v12.1\n\n  Fix problem that all apps unable to access the storage (only appears on some devices), but it brings some minor problems (only happens on limited situation), check Help for detail.\n\n* Other minor changes\n\n## 0.15.0-beta\n\n* New Enhance module (check Settings and Help)\n* File monitor: monitor file access in public storage (requires \"Enhance module\")\n* Try to fix bugs in 0.14.3\n\n## 0.14.3-beta\n\n* Try to fix bugs in 0.14.1 / 0.14.2\n* Magisk module v10 (check Help & support)\n\n## 0.14.1-beta\n\n* Provide new Magisk module to solve the problem that redirected apps still create files sometimes, check Help & support for detail\n* New native daemon\n* Adapt Magisk v16.4\n* Improve UI\n* App list will be loaded correctly now even if instant app is installed (Android 8.0's bug)\n\n## 0.12.13-beta\n\n* Link rule: fix the problem that some files are skipped\n\n## 0.12.12-beta\n\n* Fix the problem that some processes are ignored on **some special ROMs**\n* Link rule: ignore file which extension ends with _tmp_ or _temp_ by default\n\n## 0.12.11-beta\n\n* Some bug fix\n\n## 0.12.7-beta\n\n* Fix the problem that some process is not redirected (from 0.12.6)\n* Link rule: handle file downloaded notification by our app\n\n## 0.12.6-beta\n\n* Should work on Android P DP1\n* Link rules ignore .tmp / .temp by default\n* Some minor changes\n\n## 0.12.5-beta\n\n* Update Magisk module (download from Help & support)\n* Some minor changes\n\n## 0.12.4-beta\n\n* New link rules UI\n* Mark outdated (not exists in online configuration) link rules\n* Try to avoid some magic\n* Add \"Share helper\"\n\n## 0.12.3-beta\n\n* Add more log for starter\n* More core files to /data/adb\n* Try to avoid strange behavior on some devices when using Magisk module\n\n## 0.12.1-beta\n* **The core feature should works perfectly on all devices**\n* Provide Magisk module for starting before all apps (see Help & support)\n\n## 0.12.0-beta\n\n* Fix major issue on some devices\n* Add tip when log may be disabled\n* Linked files will only be deleted when redirected app is running in the foreground\n\n## 0.11.2-beta\n\n> Version 0.11.2 changed some implementation details, to avoid some magic problems on users who have problems using version 0.11.0\n\n* Should work on more devices now, to the user who still have problem, the problem should not break all things\n* Storage permission (both runtime permission and appops) will be automatically grant to redirected apps (to avoid magic problem)\n\n## 0.11.0-beta\n\n> In 0.11.0 and later version, we use a completely different method of implementation. The problem that hard-coded `/sdcard` cannot be redirected is solved.\n> If you have problem using the new version, please contact us for help.\n\n* A completely different implementation, guarantee that all files will be redirected (**Read help in \"Help & support\" for more detail**)\n* Server can be restarted without rebooting (**Reboot is required if upgrade from 0.9.x**)\n* Add redirected file browser\n* Add logcat\n* Add detailed help\n* Add \"verified app\" mark which means the app will never write files in non-standard dictionaries\n* Remove \"Block writing file\" feature since it is unnecessary now\n* Fix bug about link"
  },
  {
    "path": "storage_redirect/zh-hant/download.md",
    "content": "# 下載\n\n**需求:** 已 root 的 Android 6.0 以上裝置\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.redirectstorage)（自動選擇架構）\n\n[Coolapk](https://www.coolapk.com/apk/moe.shizuku.redirectstorage)（arm64 版本）\n\n[GitHub](https://github.com/RikkaApps/StorageRedirect-assets/releases)（全部架構，**Samsung 用戶請在這裏下載 arm 版本**）\n\n::: warning\n**Samsung 用戶**\n\n由於 Samsung 裝置內核的一些不明原因，**Samsung 裝置只能使用 arm 版本**。\n:::"
  },
  {
    "path": "storage_redirect/zh-hant/guide/README.md",
    "content": "# 介紹\n\n截至本文編寫的時間（2023-03-06），在 Android 系統中應用程式對公共儲存空間的濫用仍然是一個沒有解決的問題。\n\n儲存空間隔離致力於在儘可能小或不影響應用程式功能的前提下，解決這一問題。\n\n要清楚地說明這個問題，我們不得不先引入一些技術性的概念。\n\n### Android 系統對於儲存空間的設計\n\nAndroid 系統為應用程式提供了兩大類共三處儲存其檔案的位置，它們分別為：\n\n#### data 區域\n\n對應的資料夾：\n\n- `/data/user/<user_id>/<package_name>`\n- `/storage/emulated/<user_id>/Android/data/<package_name>`\n\n> `<user_id>` 為使用者 ID，涉及 Android 的多使用者/工作資料機制，與本文主題無關。\n>\n> `<package_name>` 為應用程式的唯一 ID。\n\n這兩個資料夾應該用於儲存應用程式自身的資料，具有如下特點：\n\n- 應用程式無需請求權限即可使用\n- 只有應用程式自身可以訪問\n- 在解除安裝應用程式或清除應用程式資料後會被刪除\n\n> `/storage/emulated/<user_id>/Android/data/<package_name>` 與 `/data/user/<user_id>/<package_name>` 的用處相同。它的存在是因為一些歷史原因：在 Android 4.x 及更早的時代，裝置自帶的儲存空間通常非常小，外接 SD 卡會被用來擴充套件儲存空間，此處便也被用作儲存應用程式自身的資料。\n\n#### 內部儲存空間\n\n對應的資料夾：\n\n- `/storage/emulated/<user_id>`\n\n此處應存放對使用者有用的檔案，例如使用者在應用程式中儲存的圖片。Android 系統提供了 `DCIM`、`Download`、`Pictures` 等公共資料夾用於分門別類地儲存照片、下載的檔案等。此處還可以被成為「共享儲存空間」、「公共儲存空間」等。\n\n具有如下特點：\n\n- 需要儲存權限才可以讀取\n- 需要儲存權限才可以寫入<sup>**〔1〕**</sup>\n- 擁有儲存權限的應用程式可以讀取其中所有的檔案，包括由其他應用程式、使用者寫入的檔案\n- 在解除安裝應用程式或清除應用程式資料後，應用程式寫入的檔案不會被刪除\n\n<sub>**〔1〕** 在 Android 11 後有變化，請參考下文</sub>\n\n### 應用程式訪問檔案的方式\n\n除了最基本的直接透過檔案路徑訪問以外，Android 系統還提供了其他幾種方式。\n\n* 媒體儲存\n\n  媒體儲存是一個系統應用程式，其內部有一個包含內部儲存空間中所有檔案資訊的資料庫。最常見的用例是，從媒體儲存查詢所有的圖片檔案。讀取、寫入檔案也可以透過媒體儲存進行。\n\n* 儲存訪問框架（Storage Access Framework，簡稱 SAF）\n\n  SAF 是一個 Android 4.4 起新增的功能。藉助 SAF，使用者可以從一個統一的由系統提供的 UI 進行開啟檔案、儲存檔案等操作。應用程式程式還可以自己成為一個提供程式，其他使用 SAF 的應用程式便可使用它。\n\n  SAF 的好處是應用程式僅可使用由使用者選擇的檔案、統一的 UI、應用程式無需請求權限等等。\n  \n  但是，多數應用程式還是更傾向於請求儲存權限後自己實現需要的功能。\n\n### 什麼是應用程式濫用儲存空間的問題\n\n對儲存空間的濫用是對「內部儲存空間」的濫用。\n一些應用程式或一些 SDK 會希望自己的資料檔案在解除安裝後不會被刪除，因此它們會選擇「內部儲存空間」寫入其資料檔案。\n\n如果應用程式有「傳送圖片」、「儲存檔案」等功能，使用者很多時候就不得不授予應用程式儲存權限。它們就會藉此在「內部儲存空間」寫入一大堆奇奇怪怪的資料夾（見下圖）。久而久之使用者的儲存空間將變得混亂無比。\n\n::: details 例子\n\n許多濫用儲存空間的應用程式建立一堆奇奇怪怪的資料夾，甚至以「SystemConfig」命名來讓使用者誤以為是系統檔案。\n\n<img :src=\"$withBase('/images/chaos_storage.png')\" alt=\"例子\">\n:::\n\n#### Android 11 新增的 Scoped storage\n\n許多人認為「Scoped storage」能夠解決這個問題，但是事實並非如此。\n\n受「Scoped storage」限制的應用程式在使用公共儲存空間時的行為會發生如下的變化：\n\n- 僅可在公共資料夾中寫入對應型別的檔案（但是系統只會檢查檔名稱是否符合規則）\n- 不需要任何權限即可在公共資料夾中寫入檔案（這比以前更加寬鬆！）\n\n顯然我們可以發現，仍然可以寫入任意檔案，唯一的區別僅僅是需要調整儲存檔案的位置到某個公共檔案中，調整檔名來欺騙系統。\n\n此外，「Scoped storage」僅作用於以 Android 11 或以上版本為目標平臺的應用程式（即 Target API ≥ 31）。不在 Google Play 上架的應用程式或停止更新的老應用程式不會受到限制。\n\n### 解決這個問題\n\n為了解決上面這個問題，我們創造了這個應用程式——儲存空間隔離。\n\n使用者可以為特定的應用程式啟用隔離。應用程式所使用的「內部儲存空間」實際將變為 `/storage/emulated/<user_id>/Android/data/<package_name>` 中的一個資料夾。因此，真正的「內部儲存空間」將不會被汙染，其建立的檔案也會在解除安裝後得以刪除。\n\n我們提供了多種機制來保證被隔離的應用程式在需要使用「內部儲存空間」中的檔案時工作正常。請閱讀後續的文件。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/advanced/shared_user_id.md",
    "content": "# 程式組\n\nAndroid 系統的 Shared User ID 機制允許多個應用程式享有相同的 Linux user ID 及 Android 權限，相互訪問檔案甚至執行在同一個行程。這些應用程式需要有具有相同簽名。Shared User ID 不可在安裝後更改。為了簡化理解難度，我們在儲存空間隔離內稱 Shared User ID 機制為程式組。\n\n這意味著：\n\n* 一些沒有儲存權限的應用程式實際可以使用儲存空間\n* 多個應用程式可以執行在同一個行程\n\n隔離作用於行程層面。在 v4.0.0 之前的版本中，只有 package name 被用作判斷，這顯然會產生問題。\n\n### 例子\n\n媒體儲存、下載管理器、下載管理器 UI、MTP 主機擁有同一個 Shared User ID `android.media`，其中媒體儲存和下載管理器都設定了 `android:process=\"android.process.media\"`。因此媒體儲存和下載管理器執行在同一個行程。\n\n在 MIUI（或許還包括其他重度修改的系統）中，下載管理器有濫用儲存空間的行為，因此使用者會選擇為其啟用隔離並只允許其訪問 `Download` 資料夾。但由於媒體儲存也運行同一行程，因此媒體儲存實際也只能訪問 `Download`，這會造成使用者相簿無法更新。\n\n另外，Shared User ID 機制可以做到使沒有儲存權限使用儲存空間。同樣是 MIUI（或許還包括其他重度修改的系統），使用者會沒有機會為這樣的應用程式啟用隔離，因為在舊版本中它們不會被展示。\n\n因此 v4.0.0 後讓相同 Shared User ID 的應用程式使用相同的設定可以解決這個問題。\n\n### 行為\n\n假設有兩個應用程式 `com.example` `com.example2`，它們的 Shared User ID 是 `example`。\n\n* 使用相同的設定（在內部被視為「同一個應用程式」）\n* 隔離儲存空間位置位於 `Android/data/shared-example` 中\n* 可相互訪問應用程式專有資料夾"
  },
  {
    "path": "storage_redirect/zh-hant/guide/advanced/technical_details_export_isolated_files.md",
    "content": "# 技術細節（匯出被隔離的檔案）\n\n假設有一個應用程式 `com.example` 儲存圖片至 `images` 資料夾。建立了一條來源資料夾 `images`，目標資料夾 `Pictures/Example` 的規則。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard      <---- com.example 的隔離儲存空間\n│       └───images  <---- 儲存圖片的位置（來源資料夾）\n│           ├───1.jpg\n│           └───...\n└───Pictures\n    └───Example     <---- 匯出後的位置（目標資料夾）\n        ├───1.jpg\n        └───...\n```\n\n建立規則後，`Android/data/com.example/sdcard/images` 資料夾會被使用 [`inotify`](http://man7.org/linux/man-pages/man7/inotify.7.html) 監視並遵循如下的規則將其中的檔案使用 [`link` (hard link)](http://man7.org/linux/man-pages/man2/link.2.html) 「同步」至 `Pictures/Example`。\n\n因為使用 hard link，所以只會佔用一份儲存空間。其他 app 或系統可能會因為沒有正確地處理這樣的情況而錯誤地回報使用情況。\n\n規則的行為：\n* 在來源資料夾中建立檔案/移動檔案至來源資料夾：link 至目標資料夾\n* 刪除/移出來源資料夾中的檔案：若應用程式在前臺則同時刪除目標資料夾中的檔案；若不在前臺則什麼都不做（這是為了避免使用者/系統/第三方應用程式操作來來源資料夾而導致檔案丟失）\n* 在目標資料夾中建立檔案/移動檔案至目標資料夾：在下次核心服務啟動時 link 至來源資料夾\n* 刪除/移出目標資料夾中的檔案：刪除來源資料夾中的檔案\n"
  },
  {
    "path": "storage_redirect/zh-hant/guide/compatibility/README.md",
    "content": "# 概覽\n\n* [Samsung](./samsung.md)\n* [Meizu](./meizu.md)\n* [Xiaomi (MIUI)](./miui.md)\n* 其他\n\n  * log 被關閉問題\n\n    在「開發者設定」中檢查 log 是否開啟。另外，據使用者反饋，在 Huawei EMUI 上 log 預設關閉 log。如果你在使用 EMUI，請自行查詢如何在 EMUI 上開啟 log。\n\n    或者，最簡單的方式，使用 [增強模式](./../enhanced_mode/)。\n"
  },
  {
    "path": "storage_redirect/zh-hant/guide/compatibility/meizu.md",
    "content": "# Meizu\n\n如果你可以使用 Magisk，你不會遇到問題。\n\n如果你不能使用 Magisk，不要為系統的「設定」程式（或其所屬的[程式組](./../advanced/shared_user_id.html)）啟用隔離。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/compatibility/miui.md",
    "content": "# Xiaomi（MIUI）\n\nMIUI 有一系列**預設啟用**的限制。然而這些限制過於離譜，應用程式正常的功能經常因此被破壞。\n\n更令人生氣的是，這些限制由 MIUI 的線上規則控制，並且對於 WeChat 這樣在中國大陸地區流行的應用程式不會開啟。\n\n## 「在背景彈出介面」權限預設拒絕\n\n「在背景彈出介面」權限是一個由 MIUI 新增權限，**預設為拒絕**。\n\n這是非常離譜的，因為拒絕該權限會**破壞應用程式的正常行為**。強烈建議你為所有設計優良的應用程式允許該權限。\n\n### 被破壞的功能\n\n* 輕觸「匯出被隔離的檔案」規則的通知無法開啟檔案\n* 從 Google Play 購買時出現「與 Play 商店互動期間出現錯誤」\n\n### 解決方法\n\n1. 開啟「儲存空間隔離」的應用程式資訊\n2. 輕觸「其他權限」（對於 MIUI 中國大陸版本是「權限」或「權限管理」）\n3. 將「在背景彈出介面」改為允許\n\n對於無法開啟檔案的問題，你可能還需要為負責開啟檔案的應用程式允許「在背景彈出介面」。\n\n對於 Google Play 購買問題，你還需要為 Google Play 允許「在背景彈出介面」。\n\n## MIUI 的省電預設啟用\n\n對於設計優良的應用程式，使用 MIUI 的省電功能**不會節省更多電量**，相反一些功能可能會被破壞。\n\n### 被破壞的功能\n\n尚不明確。\n\n### 解決方法\n\n1. 開啟「儲存空間隔離」的應用程式資訊\n2. 點選「省電策略」\n3. 選擇「無限制」"
  },
  {
    "path": "storage_redirect/zh-hant/guide/compatibility/samsung.md",
    "content": "# Samsung\n\n由於未知原因，在部分 Samsung 裝置上，以 root 使用者中執行 64 位可執行程式，其中 `exec` 函式必定會 `Permission denied`。\n\n解決方法很簡單，解除安裝後安裝 [arm 版本](./../../download.html)。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/contribute.md",
    "content": "# 貢獻線上規則\n\n目前需要人工在 GitHub 建立 issue。請按照下面的步驟進行。\n\n1. 如果你沒有 [GitHub](https://github.com/) 賬號，建立一個\n2. [建立新的 issue](https://github.com/RikkaApps/StorageRedirect-assets/issues/new?template=new_rule_json_zh-CN.md)\n3. 按照 issue 中的說明填寫"
  },
  {
    "path": "storage_redirect/zh-hant/guide/enhanced_mode/README.md",
    "content": "# 為何增強模式是必要的？\n\n-----------------------\n\n增強模式提供以下功能：\n\n1. 不再需要依賴 logcat 偵測 app 程序建立\n   - 規避由於日誌可能延後而導致有一小段時間應用程式不會被隔離的問題\n   - 規避 log 被關閉的問題（如 Huawei EMUI 開機時禁用 log）\n2. 開機啟動\n   - 規避定製系統禁止開機啟動的問題（包括但不限於 MIUI）\n3. 禁止系統重新掛載\n   - 規避定製系統的行為觸發重新掛載導致隔離失效（如 MIUI 11）\n4. 記錄應用程式訪問檔案行為\n4. 修改媒體儲存裝置及下載管理員的的行為，應用程式不能透過它們讀取/寫入已規定不能訪問的資料夾\n\n## 效能影響\n\n「增強模式」只帶來可以忽略不計的效能影響。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/enhanced_mode/install.md",
    "content": "# 安裝\n\n增強模組要求您的裝置首先安裝 Magisk。您可以從 [GitHub](https://github.com/topjohnwu/Magisk) 瞭解有關 Magisk 的更多資訊。\n\n:::tip 提示\n從 Magisk v24 起（於 2022-01-26 釋出），線上倉庫被移除。您只能直接下載 zip 後在 Magisk 中安裝。\n:::\n\n## Zygisk\n\n您可以在開啟 Zygisk 後使用 Zygisk 版本的增強模組（需要 v7.0.0 及以上版本的儲存空間隔離）。\n\n* [模組](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets)（選擇 Zygisk 版本）\n\n### 關於 Zygisk\n\nZygisk 是 Magisk v24 新增的功能。它與 Riru 在最終目的上類似，但細節與實現方面不同。\n\nZygisk 具有黑名單（DenyList）功能，在開啟強制黑名單（Enforce DenyList）後，Zygisk 不會為列表中的應用載入 Zygisk 模組。對於儲存空間隔離，列表中的應用程式不能隔離。請注意，**黑名單不是隱藏功能，它甚至不能隱藏 Zygisk 自身的存在**。\n\n**黑名單是一個脫離實際的功能**，因為人們顯然會又想要使用模組又想要隱藏。隱藏模組也要求不能開啟強制黑名單，否則隱藏模組也會因為不被載入而不能工作。\n\n簡而言之，使用專門的隱藏模組 Shamiko 來隱藏，永遠不要啟用強制黑名單。\n\n### 關於 Shamiko\n\nShamiko 是一個由其他人開發的隱藏模組。它可以隱藏 Magisk SU、Zygisk 自身及 Zygisk 模組。\n\nShamiko 借用了 Magisk 的黑名單。也就是說 Magisk 的黑名單是 Shamiko 的黑名單，但是為了讓 Shamiko 生效你不能開啟 Magisk 的強制黑名單選項。這有些令人困惑，但是就是這樣的。\n\n在 2022-02-02 以後在[這裡](https://lsposed.github.io/)下載 Shamiko。\n\n## Riru\n\n如果您使用舊版本的 Magisk 或是不使用 Zygisk，則還需要安裝 Riru。請下載 Riru 和 Riru 版本的增強模組並在 Magisk 中安裝。\n\n* [Riru](https://github.com/RikkaApps/Riru/releases)\n* [模組](https://github.com/RikkaApps/StorageRedirect-assets/releases/tag/assets)（選擇 Riru 版本）\n"
  },
  {
    "path": "storage_redirect/zh-hant/guide/faq/cant_find_app.md",
    "content": "# 無法找到一些應用程式\n\n只有請求了讀取<b>和</b>寫入儲存權限的應用程式會被顯示（換句話說，只請求讀取儲存權限或沒有請求儲存權限的應用程式不會顯示)。\n\n## 使用 root/adb 的應用程式\n\n使用 root 或 adb 的應用程式可以直接以 root 或 adb 身份訪問儲存空間而不受自身權限限制。\n\n> 此處的使用 adb 的應用程式不包括要求使用 adb 授予權限（`pm grant`）或進行類似操作的應用程式。\n\n## 使用 Xposed 的應用程式\n\n使用 Xposed 的應用程式通過其注入的應用程式使用儲存空間，即實際訪問儲存空間的是其注入的應用程式而不是 Xposed 模組應用程式本身。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/faq/how_to_document.md",
    "content": "# 如何使用檔案程式\n\n檔案程式是 Android 系統的一部分，好處是使用者可以藉此方便地從各種來源（任何實現了 DocumentProvider 的程式，如 Google Drive）讀取檔案。\n但壞處是檔案程式可能有些難用。此幫助將教你如何使用檔案程式。\n\n首先，如果你是第一次使用檔案程式，預設裝置的內建儲存不會顯示。\n你需要在右上角三點選單選擇「顯示內建儲存」來顯示內建儲存。\n\n接著，你需要知道通過右滑或點選左上角可以切換目前的位置。如果你首次使用，預設位置可能是「最近」，此位置無法建立檔案，你需要選擇你想要位置才可以儲存。\n\n## 找不到檔案程式？\n\n> 檔案程式的包名是 `com.android.documentui`\n\n### 使用高度定製的系統\n\n在部分高度定製的系統上（如 MIUI），檔案程式可能會被禁用甚至刪除。\n你需要自行查詢如何解決該問題。\n\n### 被禁用\n\n請前往系統設定-應用程式中尋找到檔案程式並啟用。\n\n### 被刪除\n\n檔案程式是 Android 系統的一部分。如果你發現你使用的系統確實刪除了檔案程式，**強烈建議你換用其他系統**，因為刪除重要的系統元件是很荒謬的。\n"
  },
  {
    "path": "storage_redirect/zh-hant/guide/faq/how_to_report_problems.md",
    "content": "# 回報問題\n\n該文件將教你如何回報問題。\n\n> 對於僅限於特定應用程式的問題（如無法在應用程式中找到圖片），大概率是設定不正確，請先自行嘗試閱讀其他文件瞭解如何正確設定。\n\n1. 確認你正在使用最近的版本的應用程式\n2. 描述應用程式版本（例如 v4.1.6.r2361）\n3. 清晰地描述你的問題\n4. 附上問題出現期間的 log（如果可以，指出問題發生的大概時間）\n5. 傳送至 [support@rikka.app](mailto://support@rikka.app)\n\n如果回報不符合要求，很大機率不會收到回覆。\n\n### 如何抓取 log\n\n你可以使用應用程式內的 logcat（主介面右上角 - Logcat）來抓取 log。\n\n注意，要抓取有意義的 log，**你需要在開始 log 後重現問題**。\n\n### 無法進入系統\n\n如果無法進入系統，則需要通過 adb 抓取 log（需要連線電腦）。關於如何使用 adb，請自己搜尋。\n\n在開機過程中連線 USB，在 adb 連線後立即執行 `adb logcat > 1.txt`。"
  },
  {
    "path": "storage_redirect/zh-hant/guide/tutorial.md",
    "content": "# 教程\n\n## 啟用隔離後會發生什麼？\n\n假設存在一個應用程式 ExampleApp（包名為 `com.example`），它使用了有濫用儲存空間行為的 SDK（假設它會建立 `bad_sdk` 資料夾）。那麼在授予 ExampleApp 儲存權限後，你的儲存空間將會是這樣的。\n\n```\n/storage/emulated/0\n├───Android\n├───bad_sdk\n├───DCIM\n├───Download\n├───Pictures\n└───...\n```\n\n現在，我們對 ExampleApp 啟用隔離，它的儲存空間成為其數據資料夾中的一個資料夾。我們稱該資料夾為「隔離儲存空間」。\n\nExampleApp 會只能使用該資料夾內的檔案，由它建立的資料夾也會保存於該資料夾。\n\n```\n/storage/emulated/0\n├───Android/data/com.example  <---- ExampleApp 的數據資料夾\n│   └───sdcard                <---- 隔離儲存空間\n│       └───bad_sdk\n└...\n```\n\n另外，由於選用了它的數據資料夾，我們還可以取得這些好處：\n\n* 解除安裝或清除數據時，這些檔案會被一併刪除\n* 在系統的應用資訊中，這些檔案也會被計入儲存空間使用量\n\n## 針對新使用者的知識\n\n::: details <b>推薦的組織檔案的方式</b>\n\n對於照片、圖片、下載的檔案等使用者檔案，Android 系統提供了一系列的標準資料夾。\n\n* `Alarms`（鬧鈴）\n* `Pictures`（圖片）\n* `DCIM`（相機）\n* `Documents`（文件）\n* `Download`（下載）\n* `Movies`（影片）\n* `Music`（音樂）\n* `Notifications`（通知音）\n* `Ringtones`（鈴聲）\n\n以最常用的 `Pictures` 為例，通行的做法是，每個應用程式各自在其中建立自己的資料夾。比如 Twitter 儲存圖片至 `Pictures/Twitter`。\n\n我們的建議是，按照上面的方式組織各個應用程式儲存的檔案。\n:::\n\n::: details <b>清理/移動已有的檔案</b>\n\n由於 `/storage/emulated` 中的檔案並沒有所有者，我們無法自動地幫助你移動或刪除已有的檔案。\n\n* 使用者檔案，如圖片\n\n  按照上面推薦的方式進行整理。\n\n* 其他\n\n  對於絕大多數應用程式，刪除先前的檔案不會產生問題。但以防萬一，我們建議你跟隨下面的步驟。\n\n  1. 建立一個臨時資料夾並將它們都移入其中。\n  2. 執行所有被隔離的應用程式。\n  3. 如果有應用程式因為無法找到之前的檔案而不正常工作，你可以藉助「檢視隔離儲存空間」功能瞭解特定資料夾可能由誰建立並由此移動那些資料夾。\n  4. 所有應用程式都正常工作後，刪除臨時資料夾。\n:::\n\n::: details <b>忘掉「清理程式」</b>\n\n一些「清理程式」有清理特定應用程式建立的檔案的功能（那些檔案不在資料資料夾中，解除安裝後不會被刪除），這種功能在隔離後因為檔案位置變化而無法使用。\n\n但是在隔離後，應用程式建立的檔案都保存於隔離儲存空間內（位於其資料資料夾），它們會在解除安裝後被刪除。另外，你可以將隔離儲存空間位置設定為快取資料夾，快取資料夾會被 Android 系統自動清理。\n\n忘掉「清理程式」吧，它們已不再有用。並且，它們從一開始就不應該存在。\n:::\n\n::: details <b>「備份程式」不會受影響（甚至可以備份更多內容）</b>\n\n「備份程式」只能備份應用程式的數據資料夾中的檔案。\n\n隔離後，應用程式建立的檔案都儲存於隔離儲存空間內（位於其數據資料夾），因此它們也能被備份了。注意，你可能需要在你的「備份程式」中啟用類似於「備份外部資料」的選項。\n:::\n\n::: details <b>使用增強模式</b>\n\n增強模式是一個非常重要的組成部分，[許多問題](./enhanced_mode/)在使用增強模式的情況下才可以解決。\n\n我們建議，當你確認一切正常後就開始嘗試增強模式（在應用程式內可以看到如何使用增強模式）。\n:::\n\n## 應用程式不正常工作的解決方案\n\n### 應用程式需要訪問特定的檔案\n\n現在 ExampleApp 有了傳送圖片功能。但是因為被隔離，你無法在 ExampleApp 中找到你的圖片。\n\n要解決這個問題，我們只需要關注「可訪問資料夾」選項中的「共享資料夾」部分。假設我們選擇了 `DCIM` 和 `Pictures` 資料夾，ExampleApp 就可以訪問這兩個資料夾中的檔案了。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard        <---- 隔離儲存空間\n│       ├───bad_sdk\n│       ├───DCIM      <---- 真實的 DCIM\n│       └───Pictures  <---- 真實的 Pictures\n└...\n```\n\n對於其他情況，你只需要選擇對應的資料夾即可。\n\n注意，應用程式不止可以讀取，還可以寫入這些資料夾。\n \n#### 不要濫用！\n\n我們只推薦必要的資料夾設為可訪問資料夾。如果你將所有的資料夾都設為可訪問資料夾，隔離將失去意義。\n\n### 找不到應用程式儲存的檔案\n\n現在 ExampleApp 有了下載圖片功能，並且你用它下載了 `1.png`。因為被隔離，`1.png` 被儲存至隔離儲存空間，你無法在相簿應用程式中看到它。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard         <---- 隔離儲存空間\n│       ├───bad_sdk\n│       ├───DCIM\n│       ├───images\n│       │   └───1.png\n│       └───Pictures\n└...\n```\n\n要解決這個問題，我們需要建立一個「匯出被隔離的檔案」規則。\n\n```\n來源：images\n目標：Pictures/ExampleApp\n新增到媒體儲存：是\n```\n\n建立規則後，你就可以在相簿應用程式及 `Pictures/ExampleApp` 中看到 `1.png`。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard               <---- 隔離儲存空間\n│       ├───images\n│       │   └───1.png\n│       └───...\n├───Pictures\n│   └───ExampleApp\n│       └───1.png\n└...\n```\n\n注意，由於使用了 hard link，因此雖然在兩處存在相同的檔案，**但是它們只會佔用一份儲存空間**。有關「匯出被隔離的檔案」的技術細節，你可以在[這裡](./advanced/technical_details_export_isolated_files.md)閱讀。\n\n#### 使用線上規則\n\n如果線上規則中已經有了需要的規則，你只需要直接新增它們。只有沒有規則的情況或是規則有錯誤時你才需要自己編寫規則。你還可以提交你的規則到線上規則庫（通過「上傳按鈕」）。\n\n#### 不要濫用！\n\n匯出的目的是匯出**使用者檔案（由使用者發起的儲存檔案操作，如儲存圖片、下載檔案等操作）**。\n\n如果應用程式將使用者檔案儲存至私有資料夾（如 `Android/data/<package>/files/example`），此處並不屬於隔離儲存空間，不適用於匯出功能。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   ├───files                <---- 不屬於隔離儲存空間\n│   └───sdcard               <---- 隔離儲存空間\n└...\n```\n\n如果你發現應用程式將**使用者檔案**儲存於私有資料夾，你應該要求它們的開發者做出改變。\n\n::: details 為什麼應該要求應用程式開發者做出改變？\n\n在 Android 11 中，`Android` 資料夾是真正的私有資料夾。即使有儲存權限，應用程式也只能訪問其中屬於自己的部分。\n\n```\n/storage/emulated/0\n├───Android\n│   ├───data\n│   │   └───com.example     <---- 屬於 com.example\n│   ├───media\n│   │   └───com.example     <---- 屬於 com.example\n│   └───obb\n│       └───com.example     <---- 屬於 com.example\n└...\n```\n\n將使用者檔案存放在私有資料夾意味著只有應用自己能看見，**其它任何應用程式，包括檔案管理器，都看不到**。這麼做顯然是不對的。另外，此處的檔案會在解除安裝或清除資料時被刪除，將使用者檔案保存於此顯然不合適。\n\n注意，對於「聊天程式中接收檔案」這樣的場景，將檔案先存放於私有資料夾是合理的。因此，在向應用程式開發者反饋時，訴求應該是新增“儲存到下載”功能（將私有資料夾中的檔案移動至 `Download` 資料夾）而不是直接改變檔案的位置。\n:::\n\n::: details 另一種「解決方案」\n\n<https://github.com/RikkaApps/SaveCopy>\n:::\n\n### 配合另外的應用程式使用時出現問題\n\n#### 使用其他應用程式檢視檔案（標準方式，即 ACTION_VIEW）\n\n現在 ExampleApp 有了使用其他應用程式開啟圖片的功能。很不幸 ExampleApp 直接將檔案路徑傳遞給其他應用程式（這種做法幾年前就應該被拋棄！），你會發現其他應用程式提示「找不到檔案」。\n\nExampleApp 自己並不會知道自己被隔離了，它所看到的儲存空間是這樣的。\n\n因此，情況是這樣的。\n\n> ExampleApp：給你， `example_app/1.png`。\n>\n> 圖片檢視器：讓我們看看試試開啟這個檔案... 誒~好像並沒有這個檔案誒！\n\n我們都知道檔案實際是位於 `/storage/emulated/0/Android/data/com.example/sdcard/images/1.png`。\n\n::: tip 不再需要對這種情況提供支援\n\n在 Android 11 中 `Android` 資料夾是真正的私有資料夾，這種做法不能正常工作。這麼做的應用程式一定會做出改變。因此，從 v4.4.0 起，對這種情況的支援被移除。\n:::\n\n#### 以非標準方式將檔案路徑傳遞給其他被隔離的應用程式\n\n現在 ExampleApp 添加了向 ExampleSocial 分享圖片的功能（ExampleSocial 也是一個被隔離的應用程式）。很不幸 ExampleSocial 要求使用它的 SDK（這種做法也應該被拋棄！），這意味著又是直接傳遞檔案路徑，並且我們無法通過「修復應用程式間互動」功能改變傳遞的檔案路徑。\n\n假設 ExampleSocial 的 SDK 是這樣工作：將圖片儲存至 `tmp` 資料夾，將檔案路徑傳遞給 ExampleSocial。\n\n```\n/storage/emulated/0\n├───Android/data/com.example\n│   └───sdcard    <---- ExampleApp 的隔離儲存空間\n│       └───tmp/shared_image\n└───Android/data/com.social.example\n│   └───sdcard    <---- ExampleSocial 的隔離儲存空間\n│       └───...\n└...\n```\n\n顯然，對於 ExampleSocial，`tmp` 資料夾並不存在，因此分享會失敗。\n\n要解決這個問題，我們需要建立一個「可訪問資料夾」-「其他程式的資料夾」規則。\n\n```\n來源應用程式：ExampleApp\n目標應用程式：ExampleSocial\n共享資料夾：tmp\n```\n\n這樣 ExampleSocial 就可以訪問來自 ExampleApp 的 `tmp` 資料夾。\n\n#### 如何建立自己的規則？\n\n你需要拿起你的「武器」——「檔案監視」。檔案監視是增強模式的功能。\n\n繼續上面的例子，在 ExampleApp 分享到 ExampleSocial 失敗後，你可以在檔案監視中看到來自 ExampleApp 和 ExampleSocial 的 `tmp` 資料夾的記錄。由此可以知道，你需要建立訪問 `tmp` 資料夾的規則。\n\n#### 使用線上規則\n\n如果線上規則中已經有了需要的規則，你只需要直接新增它們。只有沒有規則的情況或是規則有錯誤時你才需要自己編寫規則。你還可以提交你的規則到線上規則庫（通過「上傳按鈕」）。\n\n#### 補充包\n\n::: details <b>涉及 Xposed 模組</b>\n\n首先，你需要了解，Xposed 模組不止以模組應用程式本身執行，它還會在其他應用程式中執行。\n\n比如一個名為 ExampleXposedModule 的模組有修改 ExampleApp 的功能，那麼它也會在 ExampleApp 中執行。如果 ExampleXposedModule 通過建立檔案的方式儲存設定，ExampleApp 就也需要去讀取儲存的檔案，就會產生與 ExampleApp 分享到 ExampleSocial 同樣的情況。\n\n你需要做的還是藉助「檔案監視」監視瞭解哪些檔案被使用並建立對應的規則。\n\n**但是，最正確的做法應該是要求 Xposed 模組開發者做出更改！**（要求模組開發者使用 `ContentProvider` 共享配置，或是直接將配置保存於目標應用程式的資料資料夾。）\n:::\n"
  },
  {
    "path": "webhooks/.gitignore",
    "content": "/node_modules\npackage-lock.json\nconfig.json\n"
  },
  {
    "path": "webhooks/index.js",
    "content": "console.log(`CWD: ${process.cwd()}`)\n\nconst { port, secret, sites, cf_email, cf_key, cf_zone_id } = require(`${process.cwd()}/config.json`)\nconst http = require('http')\nconst request = require('request-promise')\nconst crypto = require('crypto')\nconst {\n    spawn\n} = require('child_process')\nconst fs = require('fs')\nconst path = require('path')\nconst vuepress = require('vuepress')\n\nconsole.log(`Port: ${port}`)\nconsole.log(`Secret: ${secret}`)\nconsole.log(`CF_Email: ${cf_email}`)\nconsole.log(`CF_Key: ${cf_key}`)\nconsole.log(`CF_Zone_Id: ${cf_zone_id}`)\n\nasync function buildVuePress(path) {\n    const app = vuepress.createApp({\n        sourceDir: path,\n    })\n    await app.process()\n    return app.build()\n}\n\nasync function purgeCloudflareCache(urls) {\n    for (let index = 0; index < urls.length; index += 30) {\n        let sliced = urls.slice(index, index + 30 < urls.length ? urls.length : index + 30)\n        try {\n            let res = await request(\n                {\n                    url: `https://api.cloudflare.com/client/v4/zones/${cf_zone_id}/purge_cache`,\n                    method: 'POST',\n                    body: {\n                        \"files\": sliced\n                    },\n                    json: true,\n                    headers: {\n                        \"X-Auth-Email\": cf_email,\n                        \"X-Auth-Key\": cf_key\n                    }\n                })\n            console.log(JSON.stringify(res))\n        } catch (e) {\n            console.log(JSON.stringify(e))\n        }\n    }\n}\n\nfunction collectTargets(body) {\n    let targets = new Set()\n    body.commits.forEach(commit => {\n        let changes = commit.added.concat(commit.removed).concat(commit.modified)\n        changes.forEach(change => {\n            let i = change.indexOf('/')\n            if (i != -1) {\n                let target = change.substring(0, i)\n                if (target in sites) {\n                    targets.add(target)\n                }\n            }\n        })\n    })\n\n    return targets\n}\n\nfunction collectFiles(parent, files) {\n    fs.readdirSync(parent).forEach(file => {\n        var child = parent + path.sep + file;\n        if (fs.lstatSync(child).isDirectory()) {\n            collectFiles(child, files);\n        } else {\n            files.push(parent + path.sep + file);\n        }\n    });\n}\n\nfunction collectUrls(target, path) {\n    let urls = new Set()\n\n    let files = []\n    collectFiles(path, files)\n    for (const file of files) {\n        urls.add(`https://${sites[target]}/${file.replace(path, \"\").replace(/\\\\/g, \"/\").substring(1)}`)\n    }\n\n    return urls\n}\n\nhttp.createServer(function (req, res) {\n    let body = []\n\n    req.on('error', (err) => {\n        console.error(err)\n    }).on('data', function (data) {\n        body.push(data)\n    }).on('end', async () => {\n        res.on('error', (err) => {\n            console.error(err)\n        })\n\n        body = Buffer.concat(body).toString()\n\n        let sig = \"sha1=\" + crypto.createHmac('sha1', secret).update(body).digest('hex')\n\n        if (process.env.NODE_ENV === 'production') {\n            if (req.headers['x-hub-signature'] != sig) {\n                console.error(`bad request: ${req.headers['x-hub-signature']} rather than ${sig}`)\n                res.statusCode = 403\n                res.end()\n                return\n            }\n        }\n\n        let targets\n        try {\n            targets = collectTargets(JSON.parse(body))\n        } catch (e) {\n            console.log(e)\n            res.write(e.toString())\n            res.write('\\n')\n        }\n        targets.forEach(value => {\n            res.write(`Site https://${sites[value]} requires rebuild.\\n`)\n            console.log(`Site https://${sites[value]} requires rebuild`)\n        })\n\n        res.write(\"Calling git pull...\\n\")\n        console.log(\"Calling git pull\")\n        let child = spawn('git', ['pull'])\n        child.stdout.on('data', function (data) {\n            res.write(data)\n            console.log(data.toString())\n        })\n        child.stderr.on('data', function (data) {\n            res.write(data)\n            console.error(data.toString())\n        })\n        child.on('close', async (code) => {\n            res.write(`Child process exited with code ${code}`)\n            console.log(`Child process exited with code ${code}`)\n\n            res.statusCode = 200\n            res.end()\n\n            for (const target of targets) {\n                console.log(`vuepress build ../${target}...`)\n                await buildVuePress(`../${target}`)\n                console.log(`purge Cloudflare cache...`)\n\n                let urls = collectUrls(target, `../${target}/.vuepress/dist`)\n                urls.forEach(value => {\n                    console.log(`Url ${value} requires purge cache`)\n                })\n                await purgeCloudflareCache(urls)\n            }\n        })\n    })\n}).listen(port);"
  },
  {
    "path": "webhooks/package.json",
    "content": "{\n  \"name\": \"webhooks\",\n  \"version\": \"0.1.0\",\n  \"description\": \"\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"start-debug\": \"node --nolazy --inspect-brk=9229 index.js\",\n    \"start-production\": \"NODE_ENV=production node index.js\",\n    \"test\": \"echo \\\"Error: no test specified\\\" && exit 1\"\n  },\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/RikkaApps/websites.git\"\n  },\n  \"author\": \"Rikka\",\n  \"dependencies\": {\n    \"esm\": \"^3.2.25\",\n    \"moment\": \"^2.24.0\",\n    \"request-promise\": \"^4.2.5\",\n    \"vuepress\": \"^1.2.0\",\n    \"vuepress-plugin-sitemap\": \"^2.3.1\"\n  }\n}\n"
  },
  {
    "path": "www/.gitignore",
    "content": "/.vuepress/dist"
  },
  {
    "path": "www/.vuepress/config.js",
    "content": "const moment = require('moment')\nconst langMap = {\n  \"zh-Hans\": \"zh-cn\",\n  \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}\n\nmodule.exports = {\n  base: '/',\n  title: 'Rikka Apps',\n  head: [\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    ['link', {\n      rel: 'stylesheet',\n      href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',\n      media: 'print',\n      onload: \"this.media='all'\"\n    }],\n    /*['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],\n    ['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],\n    ['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]*/\n  ],\n  locales: {\n    '/': {\n      lang: 'en',\n      description: 'Create Android apps with love & magic.'\n    },\n    '/zh-hans/': {\n      lang: 'zh-Hans',\n      description: '用爱与魔法创造 Android 应用。'\n    },\n    '/zh-hant/': {\n      lang: 'zh-Hant',\n      description: '用愛與魔法創造 Android 應用程式。'\n    }\n  },\n  themeConfig: {\n    locales: {\n      '/': {\n        selectText: 'Languages',\n        label: 'English',\n        serviceWorker: {\n          updatePopup: {\n            message: \"New content is available.\",\n            buttonText: \"Refresh\"\n          }\n        },\n        sidebar: getSidebar('/knowledge/', 'Knowledge base'),\n        nav: getNavbar('/', 'Knowledge base', 'Contribute translation'),\n        lastUpdated: 'Last Updated'\n      },\n      '/zh-hans/': {\n        selectText: '语言',\n        label: '简体中文',\n        editLinkText: '在 GitHub 上编辑此页',\n        serviceWorker: {\n          updatePopup: {\n            message: \"发现新内容可用.\",\n            buttonText: \"刷新\"\n          }\n        },\n        sidebar: getSidebar('/zh-hans/knowledge/', '知识库'),\n        nav: getNavbar('/zh-hans/', '知识库', '参与翻译'),\n        lastUpdated: '最后更新'\n      },\n      '/zh-hant/': {\n        selectText: '語言',\n        label: '繁體中文',\n        editLinkText: '在 GitHub 上編輯此頁',\n        serviceWorker: {\n          updatePopup: {\n            message: \"發現新內容可用.\",\n            buttonText: \"重新整理\"\n          }\n        },\n        sidebar: getSidebar('/zh-hant/knowledge/', '知識庫'),\n        nav: getNavbar('/zh-hant/', '知識庫', '參與翻譯'),\n        lastUpdated: '最後更新'\n      }\n    },\n    displayAllHeaders: false,\n    sidebarDepth: 2,\n    serviceWorker: {\n      updatePopup: true\n    },\n    search: false,\n    docsRepo: 'https://github.com/RikkaApps/websites',\n    docsDir: 'www',\n    editLinks: false\n  },\n  plugins: [\n    [\n      'sitemap',\n      {\n        hostname: 'https://rikka.app',\n        exclude: ['/404.html'],\n        dateFormatter: (time) => {\n          timestampCache[time]\n        }\n      }\n    ],\n    [\n      'clean-urls',\n      {\n        normalSuffix: '/',\n        indexSuffix: '/',\n        notFoundPath: '/404.html'\n      }\n    ],\n    [\n      '@vuepress/last-updated',\n      {\n        transformer: (timestamp, lang) => {\n          var original = timestamp\n\n          moment.locale(langMap[lang])\n          var localized = moment(original).format('lll')\n          \n          moment.locale('en')\n          var iso = moment(original).toISOString()\n          timestampCache[localized] = iso\n\n          return localized\n        }\n      }\n    ]\n  ]\n}\n\nfunction getSidebar(prefix, knowledgeTitle) {\n  var res = {}\n  res[prefix] = [\n    {\n      title: knowledgeTitle,\n      collapsable: false,\n      sidebarDepth: 2,\n      children: [\n        'google_play_purchase',\n        'exit_on_start',\n      ]\n    }]\n  return res\n}\n\nfunction getNavbar(prefix, knowledge, translation) {\n  return [\n    { text: knowledge, link: `${prefix}knowledge/google_play_purchase.md` },\n    { text: translation, link: `${prefix}contribute_translation.md` }\n  ]\n}"
  },
  {
    "path": "www/.vuepress/public/robots.txt",
    "content": "User-Agent: *\n\nDisallow: /zh-hans/transfer_china.html\nDisallow: /zh-hans/use_google_play.html"
  },
  {
    "path": "www/.vuepress/theme/components/Home.vue",
    "content": "<template>\n  <main class=\"home\" aria-labelledby=\"main-title\">\n    <header class=\"hero\">\n      <!--<img\n        class=\"background-img\"\n        v-if=\"data.backgroundImage\"\n        :src=\"$withBase(data.backgroundImage)\"\n        :alt=\"data.backgroundAlt || 'background'\"\n      >-->\n      <div class=\"header\">\n        <img\n          class=\"avator-img\"\n          v-if=\"data.heroImage\"\n          :src=\"$withBase(data.heroImage)\"\n          :alt=\"data.heroAlt || 'hero'\"\n        >\n        \n        <div class=\"header-text\">\n          <h1 v-if=\"data.heroText !== null\" id=\"main-title\">{{ data.heroText || $title || 'Hello' }}</h1>\n\n          <p class=\"description\">\n            {{ data.tagline || $description || 'Welcome to your VuePress site' }}\n          </p>\n        </div>\n      </div>\n    </header>\n\n    <div\n      class=\"apps\"\n      v-if=\"data.apps && data.apps.length\"\n    >\n      <div\n        div class=\"app\"\n        v-for=\"(app, index) in data.apps\"\n        :key=\"index\"\n      >\n        \n        <div class=\"text\">\n          <div>\n          <img class=\"icon\" align=\"middle\" v-if=\"app.icon\" :src=\"$withBase(app.icon)\"></img>\n          <span class=\"title\">{{ app.title }}</span>\n          </div>\n          <span class=\"details\" v-html=\"app.details\"/>\n        </div>\n\n        <div class=\"actions\">\n\t        <div\n              class=\"action\"\n              v-if=\"app.secondaryAction\"\n            >\n              <NavLink\n                class=\"action-button secondary\"\n                :item=\"app.secondaryAction\"\n              />\n            </div>\n\t        <div\n              class=\"action\"\n              v-if=\"app.primaryAction\"\n            >\n              <NavLink\n                class=\"action-button\"\n                :item=\"app.primaryAction\"\n              />\n            </div>\n\t      </div>\n    \n      </div>\n    </div>\n\n    <Content class=\"theme-default-content custom\"/>\n\n    <div\n      class=\"footer\"\n      v-if=\"data.footer\"\n    >\n      {{ data.footer }}\n    </div>\n  </main>\n</template>\n\n<script>\nimport NavLink from '@parent-theme/components/NavLink.vue'\n\nexport default {\n  components: { NavLink },\n\n  computed: {\n    data () {\n      return this.$page.frontmatter\n    },\n  }\n}\n</script>\n\n<style lang=\"stylus\">\n.home\n  padding $navbarHeight 2rem 0\n  max-width 960px\n  margin 0px auto\n  display block    \n  .hero\n    text-align start\n    .header\n      margin 3rem auto 1.5rem\n      display table\n    .header-text\n      display table-cell\n      vertical-align middle\n    .avator-img\n      display table-cell\n      max-width: 100%\n      display block\n      margin-right: 3rem\n      box-shadow: 0 2px 2px 0 rgba(0,0,0,0.14), 0 3px 1px -2px rgba(0,0,0,0.12), 0 1px 5px 0 rgba(0,0,0,0.2);\n      background-color #f5f5f5\n      border 5px solid #f5f5f5\n      height 144px\n      width 144px\n      border-radius: 77px\n      //margin-top: -100px\n    .background-img\n      max-width: 100%\n    h1\n      font-size 3rem\n\t h1, .description\n      margin 0 auto 1rem\n    .description\n      font-weight 300\n      max-width 35rem\n      font-size 1.6rem\n      line-height 1\n      color lighten($textColor, 40%)\n      margin 0 auto 0\n  .apps\n    //border-top 1px solid $borderColor\n    padding 0 0\n    margin-top 2.5rem\n  .app\n    display flex\n    flex-wrap wrap\n    align-items center\n    justify-content center\n    margin-top -1px\n    background-color #fff\n    transition background-color .1s ease\n    border-top 1px solid $borderColor\n    border-bottom 1px solid $borderColor\n    padding 1.5rem 3rem\n    &:hover\n      background-color lighten($textColor, 90%)\n    .title\n      vertical-align middle\n      margin 0 1rem 0\n      font-size 1.4rem\n      font-weight 500\n      border-bottom none\n      padding-bottom 0\n      color lighten($textColor, 10%)\n    .details\n      display inline-block      \n      line-height 1.3\n      margin 1rem 0 0\n      color lighten($textColor, 25%)\n    .icon\n      vertical-align middle\n      max-width 2rem\n    .text\n      flex 1\n      align-self center\n      margin 0.5rem 1rem 0.5rem\n\t  .action\n\t    margin 0.3rem\n\t  .actions\n        margin 0 1rem 0\n        align-self center\n        display flex\n        flex-wrap wrap\n        align-items flex-start\n        align-content stretch\n        justify-content center\n      .action-button\n        display inline-block\n        font-size 1rem\n        color #fff\n        background-color $accentColor\n        padding 0.6rem 1.2rem\n        border-radius 4px\n        transition background-color .1s ease\n        box-sizing border-box\n        border-bottom 1px solid darken($accentColor, 10%)\n        &:hover\n          background-color lighten($accentColor, 10%)\n\t      .secondary\n          color $textColor\n          background-color transparent\n          transition background-color .1s ease\n          border 1px solid $textColor\n          &:hover\n            background-color lighten($textColor, 95%)\n        .outbound\n          display none\n  .footer\n    padding 2.5rem\n    //border-top 1px solid $borderColor\n    text-align center\n    color lighten($textColor, 25%)\n\n@media (max-width: $MQMobile)\n  .home\n    padding-left 0\n    padding-right 0\n    .header\n      padding-left 1.5rem\n      padding-right 1.5rem\n    .app\n      align-items flex-start\n      justify-content flex-start\n      max-width 100%\n      padding 1.5rem 10%\n      .icon\n        max-width 2rem\n      .text\n        margin 0 1rem 1rem\n        flex auto\n    .hero\n      text-align center\n      .header\n        margin 3rem auto 1.5rem\n        display block\n        align-items flex-start\n        justify-content center\n      .header-text\n        display block\n        vertical-align middle\n        align-items center\n        align-content stretch\n        justify-content center\n      .avator-img\n        display block\n        margin 3rem auto 1.5rem\n\n@media (max-width: $MQMobileNarrow)\n  .home\n    .hero\n      .avator-img\n        max-height 210px\n        margin 2rem auto 1.2rem\n      h1\n        font-size 2rem\n      h1, .description, .actions\n        margin 1.2rem auto\n      .description\n        font-size 1.2rem\n      .action-button\n        font-size 1rem\n        padding 0.6rem 1.2rem\n    .app\n      padding 1.5rem 5%\n      .title\n        font-size 1.25rem\n      .action-button\n        font-size 1rem\n        padding 0.6rem 1.2rem\n</style>\n"
  },
  {
    "path": "www/.vuepress/theme/components/SidebarLink.vue",
    "content": "<script>\nimport { isActive, hashRE, groupHeaders } from '@parent-theme/util'\n\nexport default {\n  functional: true,\n\n  props: ['item', 'sidebarDepth'],\n\n  render (h,\n    {\n      parent: {\n        $page,\n        $site,\n        $route,\n        $themeConfig,\n        $themeLocaleConfig\n      },\n      props: {\n        item,\n        sidebarDepth\n      }\n    }) {\n    // use custom active class matching logic\n    // due to edge case of paths ending with / + hash\n    const selfActive = isActive($route, item.path)\n    // for sidebar: auto pages, a hash link should be active if one of its child\n    // matches\n    const active = item.type === 'auto'\n      ? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))\n      : selfActive\n    const link = item.type === 'external'\n      ? renderExternal(h, item.path, item.title || item.path)\n      : renderLink(h, item.path, item.title || item.path, active)\n\n    const maxDepth = [\n      $page.frontmatter.sidebarDepth,\n      sidebarDepth,\n      $themeLocaleConfig.sidebarDepth,\n      $themeConfig.sidebarDepth,\n      1\n    ].find(depth => depth !== undefined);\n\n    const displayAllHeaders = $themeLocaleConfig.displayAllHeaders\n      || $themeConfig.displayAllHeaders\n\n    if (item.type === 'auto') {\n      return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]\n    } else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {\n      const children = groupHeaders(item.headers)\n      return [link, renderChildren(h, children, item.path, $route, maxDepth)]\n    } else {\n      return link\n    }\n  }\n}\n\nfunction renderLink (h, to, text, active) {\n  return h('router-link', {\n    props: {\n      to,\n      activeClass: '',\n      exactActiveClass: ''\n    },\n    class: {\n      active,\n      'sidebar-link': true\n    }\n  }, text)\n}\n\nfunction renderChildren (h, children, path, route, maxDepth, depth = 1) {\n  if (!children || depth > maxDepth) return null\n  return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {\n    const active = isActive(route, path + '#' + c.slug)\n    return h('li', { class: 'sidebar-sub-header' }, [\n      renderLink(h, path + '#' + c.slug, c.title, active),\n      renderChildren(h, c.children, path, route, maxDepth, depth + 1)\n    ])\n  }))\n}\n\nfunction renderExternal (h, to, text) {\n  return h('a', {\n    attrs: {\n      href: to,\n      target: '_blank',\n      rel: 'noopener noreferrer'\n    },\n    class: {\n      'sidebar-link': true\n    }\n  }, [text, h('OutboundLink')])\n}\n</script>\n\n<style lang=\"stylus\">\n.sidebar .sidebar-sub-headers\n  padding-left 1rem\n  font-size 0.95em\n\na.sidebar-link\n  font-size 1em\n  font-weight 400\n  display inline-block\n  color $textColor\n  border-left 0.25rem solid transparent\n  padding 0.35rem 1rem 0.35rem 1.25rem\n  line-height 1.4\n  width: 100%\n  box-sizing: border-box\n  &:hover\n    color $accentColor\n  &.active\n    font-weight 600\n    color $accentColor\n    border-left-color $accentColor\n  .sidebar-group &\n    padding-left 2rem\n  .sidebar-sub-headers &\n    padding-top 0.25rem\n    padding-bottom 0.25rem\n    border-left none\n    &.active\n      font-weight 500\n</style>\n"
  },
  {
    "path": "www/.vuepress/theme/index.js",
    "content": "module.exports = {\n  extend: '@vuepress/theme-default'\n}"
  },
  {
    "path": "www/.vuepress/theme/layouts/Layout.vue",
    "content": "<template>\n  <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport default {\n  components: {\n    ParentLayout\n  }\n}\n</script>"
  },
  {
    "path": "www/.vuepress/theme/styles/index.styl",
    "content": "code\n  overflow: auto\n  word-wrap:break-word\n\nbody\n  font-family Roboto, sans-serif\n\nbody:lang(zh-hans)\n  font-family Roboto, 'Noto Sans SC', sans-serif\n\nbody:lang(zh-hant)\n  font-family Roboto, 'Noto Sans TC', sans-serif\n\n/*.site-name\n  display none !important*/\n"
  },
  {
    "path": "www/.vuepress/theme/styles/palette.styl",
    "content": "$accentColor = #D81B60\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
  },
  {
    "path": "www/README.md",
    "content": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: Storage Isolation\n  details: Give apps isolated storage, never be annoyed by messy folders created by poor-designed apps.<br><small>* Requires root</small>\n  icon: https://sr.rikka.app/logo.png\n  secondaryAction:\n    link: https://sr.rikka.app\n    text: Learn more\n  primaryAction:\n    link: https://sr.rikka.app/download.html\n    text: Download\n- title: App Ops\n  details: Control the hidden appops conveniently with App Ops app. Works without root.<br><small>* Requires adb if not rooted</small>\n  icon: https://appops.rikka.app/logo.png\n  secondaryAction:\n    link: https://appops.rikka.app\n    text: Learn more\n  primaryAction:\n    link: https://appops.rikka.app/download.html\n    text: Download\n- title: Shizuku\n  details: Help others apps to use system APIs conveniently with adb or root privilege.<br><small>* Requires adb or root</small>\n  icon: https://shizuku.rikka.app/logo.png\n  secondaryAction:\n    link: https://shizuku.rikka.app\n    text: Learn more\n  primaryAction:\n    link: https://shizuku.rikka.app/download.html\n    text: Download\n- title: NoPopping\n  details: Disable pop notification automatically by current app.\n  icon: /logo_nopooping.png\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=rikka.nopeeking\n    text: Download\n- title: WADB\n  details: Toggle \"adb over network\" from Quick Settings.<br><small>* Requires root</small>\n  icon: /logo_wadb.png\n  secondaryAction:\n    link: https://github.com/RikkaApps/WADB\n    text: Learn more\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=moe.haruue.wadb\n    text: Download\n---"
  },
  {
    "path": "www/contribute_translation.md",
    "content": "# Contribute translation\n\nRikkaApps uses self-hosted Weblate as a translation platform. Currently, we are moving the translation to this platform.\n\n1. Go to <https://weblate.rikka.app/>\n2. Log in via GitHub\n3. View all projects <https://weblate.rikka.app/projects/>, translate what you want to translate\n\n> For some nouns that appear in the Android system, you can use this website <https://translations.zhanghai.me/> to search. This site is developed by [Hai Zhang](https://github.com/zhanghai)."
  },
  {
    "path": "www/knowledge/exit_on_start.md",
    "content": "# Exit on start\n\nStorage Isolation, AppOps, and NoPopping have anti-tampering mechanisms. Once tampering is detected, the application exits on start.\n\nTampering includes, but is not limited to:\n\n* Resigning\n* Run in a virtual environment\n* Enable Xposed for the application\n  \n  Mainstream Xposed implementations have exclusion feature, please exclude apps from the Xposed framework you use.\n\nPlease make sure that the app is downloaded from official channels, including Google Play, GitHub release, Coolapk (for users in mainland China).\n\nCurrently, there are very few users reporting this issue after upgrading from different channels, but it is not certain if this is true. If this is the case for you, please sending the currently installed apk to [support@rikka.app](mailto://support@rikka.app) and reinstall the application."
  },
  {
    "path": "www/knowledge/google_play_purchase.md",
    "content": "# Purchase (restore) issues on Google Play\n\nThe whole purchase process happens in Google Play, **the app developer has zero control over it**, all these solutions are based on experience.\n\n### Multi-account issue\n\nIf you are logged into multiple accounts, Play Store may use the wrong account. This is not controlled by the app developer. Usually use the account at the time of purchase to reinstall should solve the problem.\n\nIf have joined the testing program with the account you used to purchase, you may need to exit the testing program first. None of the testing program are currently open, so you can only exit from the webpage.\n\n::: details Testing program link\n\nIf you have not joined the testing program before, you will see an error.\n\n- Storage Isolation: <https://play.google.com/apps/testing/moe.shizuku.redirectstorage>\n- AppOps: <https://play.google.com/apps/testing/rikka.appops>\n- NoPopping: <https://play.google.com/apps/testing/rikka.nopeeking>\n\n:::\n\n### Using spoof softwares\n\nSpoof softwares like \"L**** Patcher\" will hijack the connection between the app and the Play Store, which will finally result in error.\n\n### Login to too many devices\n\nGoogle may have some sort of risk control mechanism to disallow users login to too many devices to use purchased contents.\n\nIf you do factory reset or flash third-party ROMs without logout Google account first, you many have too many devices in your account.\n\nCheck [Google's device management page](https://myaccount.google.com/device-activity) and remove devices that do not exist.\n\n### Code 7\n\nThe purchase record is stored in Play Store's cache. Code 7 means the record is missing.\n\nUsually, clearing the cache of the Play Store should solve the problem.\n\n### Code 3\n\nThe region of current Google account does not support purchase. Please refer to [Google's help page](https://support.google.com/googleplay/android-developer/table/3541286).\n\nSearch how to confirm (change) the region by yourself. Remember, the region is NOT related to your network environment.\n\n### Code 6\n\nPurchase is an interaction process between the app and Play Store. Many custom systems enable some restrictions by default, so that this process is blocked. For example, on MIUI, it's required to allow \"Display interface in the background\" permission for the Play Store."
  },
  {
    "path": "www/privacy_policy.md",
    "content": "---\nnavbar: false\n---\n\n# Privacy Policy\n\nThe protection of your data is of particular concern to us. Therefore, we process your data only based on the applicable data protection laws (GDPR). We take careful precautions to protect your data from loss, manipulation, and unauthorized access. The precautions are by the current state of technology. In this statement on our Data Privacy Policy, we inform you about the most important aspects in the context of data processing in our apps.\n\nThe following applications do not collect any information.\n\n* SaveCopy\n* Shizuku\n* Key Attestation Demo\n* YASNAC\n\n## 1. Personal information\n\nIf not special specified, we do not collect and hold any information that would allow us to identify users of our apps.\n\nIn case of in-app purchases of our apps in the Google Play Store, we receive information about the purchase (order ID, purchase time, region) from Google.\n\nThe following applications have optional features which requires additional information.\n\nStorage Isolation has \"online rules\" feature. This feature is disabled by default from version 8.2.2. If this feature is enabled, in order to fetch the \"online rule\" related to the application, we collect application ID of apps on users' device. No other personal information is collected and sent. The application ID is only used to find the corresponding rule file and not stored.\n\n## 2. Anonymous identifier\n\nIn the case of in-app purchase, an anonymous identifier participate in purchase verification. The anonymous identifier is generated the first time the application is launched. Clearing the data of the application, reinstalling the application or factory resetting the device will reset the identifier. As mentioned the identifier is anonymous, we cannot trace information back to individual devices or users.\n\nThe following applications have an in-app-purchase function.\n\n* Storage Isolation\n* AppOps\n* NoPopping\n* FPS Monitor\n\n## 3. Use of third-party services \n\n### Visual Studio App Center\n\nApp Center is a product of Microsoft Corporation, it provides crash reporting function. We have the access of aggregated and anonymous information about device country settings, device languages, device names, version of operating systems, as well as the version of our apps from Visual Studio App Center. In addition, Visual Studio App Center provides us with information about app crashes. The aggregated and anonymous information is held by Microsoft Corporation.\n\nAs the mentioned aggregated data is anonymous, we cannot trace information back to individual devices or users.\n\nFurther information about privacy in Visual Studio App Center can be found from [this webpage from Visual Studio App Center](https://docs.microsoft.com/en-us/appcenter/gdpr/).\n\nThe following applications use Visual Studio App Center.\n\n* Storage Isolation\n* AppOps\n* NoPopping\n\n## 4. Your right\n\nFor applications using Visual Studio App Center mentioned in section 3, you can request for deleting the aggregated and anonymous information and the information will be deleted in 28 days.\n\n## 5. Contact \n\nContact for your privacy concerns: [support@rikka.app](mailto://support@rikka.app)"
  },
  {
    "path": "www/zh-hans/README.md",
    "content": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: 存储空间隔离\n  details: 让应用有隔离存储，再也不为设计不佳的应用创建的凌乱文件夹烦恼。<br><small>* 需要 root</small>\n  icon: https://sr.rikka.app/logo.png\n  secondaryAction:\n    link: https://sr.rikka.app/zh-hans\n    text: 了解更多\n  primaryAction:\n    link: https://sr.rikka.app/zh-hans/download.html\n    text: 下载\n- title: App Ops\n  details: 使用 App Ops 应用舒适地控制隐藏的 appops。无需 root 也可使用。<br><small>* 如果没有 root 则需要 adb</small>\n  icon: https://appops.rikka.app/logo.png\n  secondaryAction:\n    link: https://appops.rikka.app/zh-hans\n    text: 了解更多\n  primaryAction:\n    link: https://appops.rikka.app/zh-hans/download.html\n    text: 下载\n- title: Shizuku\n  details: 帮助其他应用舒适地以 adb 或 root 特权使用系统 API。<br><small>* 需要 adb 或 root</small>\n  icon: https://shizuku.rikka.app/logo.png\n  secondaryAction:\n    link: https://shizuku.rikka.app/zh-hans\n    text: 了解更多\n  primaryAction:\n    link: https://shizuku.rikka.app/zh-hans/download.html\n    text: 下载\n- title: NoPopping\n  details: 根据当前应用自动关闭弹出通知。\n  icon: /logo_nopooping.png\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=rikka.nopeeking\n    text: 下载\n- title: WADB\n  details: 从快速设置开关“网络 adb”。<br><small>* 需要 root</small>\n  icon: /logo_wadb.png\n  secondaryAction:\n    link: https://github.com/RikkaApps/WADB\n    text: 了解更多\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=moe.haruue.wadb\n    text: 下载\n---"
  },
  {
    "path": "www/zh-hans/contribute_translation.md",
    "content": "# 参与翻译\n\nRikkaApps 使用自行托管的 Weblate 作为翻译平台。目前，我们正在将翻译移动至该平台。\n\n1. 进入 <https://weblate.rikka.app/>\n2. 通过 GitHub 登录\n3. 查看所有项目 <https://weblate.rikka.app/projects/>，翻译你想要翻译的内容\n\n> 对于一些出现在 Android 系统中的名词，你可以使用这个网站 <https://translations.zhanghai.me/> 搜索。此网站由 [zhanghai](https://github.com/zhanghai) 开发。"
  },
  {
    "path": "www/zh-hans/knowledge/exit_on_start.md",
    "content": "# 启动后立刻退出\n\nStorage Isolation、AppOps 和 NoPopping 有反篡改机制。一旦检测到篡改，应用程序会在启动后立刻退出。\n\n篡改行为包括但不限于：\n\n* 重新签名\n* 在虚拟环境中运行\n* 为应用程序启用 Xposed\n  \n  主流的 Xposed 实现均有排除功能，请将应用程序从您使用的 Xposed 框架中排除。\n\n请确保应用程序是从官方渠道下载，官方渠道包含 Google Play，GitHub release，酷安（针对中国大陆地区用户）。\n\n目前，有极少数的用户报告从不同的渠道升级后出现此问题，但是尚不确定是否属实。如果您是这种情况，请将当前安装的 apk 发送到 [support@rikka.app](mailto://support@rikka.app) 后卸载重装。\n\n"
  },
  {
    "path": "www/zh-hans/knowledge/google_play_purchase.md",
    "content": "# Google Play 购买问题\n\n整个购买过程都发生在 Google Play 中，**应用开发者无法控制它**，因此所有这些解决方案都是经验之谈。\n\n### 多账号问题\n\n如果你登录了多个账号，Play 商店可能会使用错误的账号。应用开发者无法控制。通常使用购买时的账号重新安装即可解决。\n\n如果你用于购买的账号曾经加入了测试计划，你可能需要先退出测试计划。目前测试计划均未开启，因此只能从网页退出。\n\n::: details 测试计划链接\n\n如果你未曾加入测试计划，会看到错误。\n\n- 存储空间隔离：<https://play.google.com/apps/testing/moe.shizuku.redirectstorage>\n- AppOps：<https://play.google.com/apps/testing/rikka.appops>\n- NoPopping：<https://play.google.com/apps/testing/rikka.nopeeking>\n\n:::\n\n### 使用欺骗程序\n\n诸如“L**** Patcher”之类的欺骗程序会劫持应用程序与 Play 商店之间的连接，最终导致错误。\n\n### 登录到太多设备\n\nGoogle 可能具有某种风险控制机制，以禁止拥有过多设备的用户使用已购买的内容。\n\n如果您进行出厂重置或刷写第三方 ROM 前没有登出 Google 账号，您的账号中就可能有过多的设备。\n\n检查 [Google 的设备管理页面](https://myaccount.google.com/device-activity) 并删除不存在的设备。\n\n### Code 7\n\n购买记录存储在 Play 商店的缓存中。Code 7 意味着记录丢失了。\n\n通常，清除 Play 商店的缓存可以解决该问题。\n\n### Code 3\n\n当前 Google 账号所在的地区不支持购买。请参阅 [Google 的帮助页面](https://support.google.com/googleplay/android-developer/table/3541286)。\n\n请自行搜索如何确认（改变）账号区域。记住，地区与你的网络环境无关。\n\n### Code 6\n\n购买是一个应用与 Play 商店交互的过程。许多定制系统默认启用一些限制导致该过程受阻。比如，MIUI 需要为 Play 商店允许“在后台显示界面”权限。"
  },
  {
    "path": "www/zh-hant/README.md",
    "content": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: 儲存空間隔離\n  details: 讓應用有隔離儲存，再也不為設計不佳的應用程式建立的凌亂資料夾煩惱。<br><small>* 需要 root</small>\n  icon: https://sr.rikka.app/logo.png\n  secondaryAction:\n    link: https://sr.rikka.app/zh-hant\n    text: 瞭解更多\n  primaryAction:\n    link: https://sr.rikka.app/zh-hant/download.html\n    text: 下載\n- title: App Ops\n  details: 使用 App Ops 程式舒適地控制隱藏的 appops。無需 root 也可使用。<br><small>* 如果沒有 root 則需要 adb</small>\n  icon: https://appops.rikka.app/logo.png\n  secondaryAction:\n    link: https://appops.rikka.app/zh-hant\n    text: 瞭解更多\n  primaryAction:\n    link: https://appops.rikka.app/zh-hant/download.html\n    text: 下載\n- title: Shizuku\n  details: 幫助其他應用程式舒適地以 adb 或 root 特權使用系統 API。<br><small>* 需要 adb 或 root</small>\n  icon: https://shizuku.rikka.app/logo.png\n  secondaryAction:\n    link: https://shizuku.rikka.app/zh-hant\n    text: 瞭解更多\n  primaryAction:\n    link: https://shizuku.rikka.app/zh-hant/download.html\n    text: 下載\n- title: NoPopping\n  details: 根據當前應用程式自動關閉彈出通知。\n  icon: /logo_nopooping.png\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=rikka.nopeeking\n    text: 下載\n- title: WADB\n  details: 從快速設定開關「網路 adb」。<br><small>* 需要 root</small>\n  icon: /logo_wadb.png\n  secondaryAction:\n    link: https://github.com/RikkaApps/WADB\n    text: 瞭解更多\n  primaryAction:\n    link: https://play.google.com/store/apps/details?id=moe.haruue.wadb\n    text: 下載\n---"
  },
  {
    "path": "www/zh-hant/contribute_translation.md",
    "content": "# 參與翻譯\n\nRikkaApps 使用自行架設的 Weblate 作為翻譯平臺。目前，我們正在將翻譯移動至該平臺。\n\n1. 進入 <https://weblate.rikka.app/>\n2. 透過 GitHub 登入\n3. 檢視所有專案 <https://weblate.rikka.app/projects/>，翻譯你想要翻譯的內容\n\n> 對於一些出現在 Android 系統中的名詞，你可以使用這個網站 <https://translations.zhanghai.me/> 搜尋。此網站由 [zhanghai](https://github.com/zhanghai) 開發。"
  },
  {
    "path": "www/zh-hant/knowledge/exit_on_start.md",
    "content": "# 啟動後立刻退出\n\nStorage Isolation、AppOps 和 NoPopping 有反篡改機制。一旦檢測到篡改，應用程式會在啟動後立刻退出。\n\n篡改行為包括但不限於：\n\n* 重新簽名\n* 在虛擬環境中執行\n* 為應用程式啟用 Xposed\n  \n  主流的 Xposed 實現均有排除功能，請將應用程式從您使用的 Xposed 框架中排除。\n\n請確保應用程式是從官方渠道下載，官方渠道包含 Google Play，GitHub release，酷安（針對中國大陸地區使用者）。\n\n目前，有極少數的使用者報告從不同的渠道升級後出現此問題，但是尚不確定是否屬實。如果您是這種情況，請將當前安裝的 apk 傳送到 [support@rikka.app](mailto://support@rikka.app) 後解除安裝重灌。\n"
  },
  {
    "path": "www/zh-hant/knowledge/google_play_purchase.md",
    "content": "# Google Play 購買問題\n\n整個購買過程都發生在 Google Play 中，**應用程式的開發人員無法控制它**，因此所有這些解決方案都是經驗之談。\n\n### 多賬號問題\n\n如果你登入了多個賬號，Play 商店可能會使用錯誤的賬號。開發人員無法控制。通常使用購買時的賬號重新安裝即可解決。\n\n如果你用於購買的賬號曾經加入了測試計劃，你可能需要先退出測試計劃。目前測試計劃均未開啟，因此只能從網頁退出。\n\n::: details 測試計劃連結\n\n如果你未曾加入測試計劃，會看到錯誤。\n\n- 儲存空間隔離：<https://play.google.com/apps/testing/moe.shizuku.redirectstorage>\n- AppOps：<https://play.google.com/apps/testing/rikka.appops>\n- NoPopping：<https://play.google.com/apps/testing/rikka.nopeeking>\n\n:::\n\n### 使用欺騙程式\n\n諸如「L**** Patcher」之類的欺騙程式會劫持應用程式與 Play 商店之間的連線，最終導致錯誤。\n\n### 登入到太多裝置\n\nGoogle 可能具有某種風險管理機制，以禁止擁有過多裝置的使用者使用已購買的內容。\n\n如果您恢復原廠設定或刷寫第三方 ROM 前沒有登出 Google 賬號，您的賬號中就可能有過多的裝置。\n\n檢查 [Google 的裝置管理頁面](https://myaccount.google.com/device-activity) 並刪除不存在的裝置。\n\n### Code 7\n\n購買記錄儲存在 Play 商店的快取中。Code 7 意味著記錄丟失了。\n\n通常，清除 Play 商店的快取可以解決該問題。\n\n### Code 3\n\n當前 Google 賬號所在的地區不支援購買。請參閱 [Google 的幫助頁面](https://support.google.com/googleplay/android-developer/table/3541286)。\n\n請自行搜尋如何確認（改變）賬號區域。記住，地區與你的網路環境無關。\n\n### Code 6\n\n購買是一個應用程式與 Play 商店互動的過程。許多定製系統預設啟用一些限制導致該過程受阻。比如，MIUI 需要為 Play 商店允許「在背景顯示界面」權限。"
  }
]