Showing preview only (505K chars total). Download the full file or copy to clipboard to get everything.
Repository: RikkaApps/websites
Branch: master
Commit: 66a2bc3549a5
Files: 177
Total size: 361.6 KB
Directory structure:
gitextract_c9c7yzyg/
├── .gitattributes
├── .github/
│ └── dependabot.yml
├── .gitignore
├── appops/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── Home.vue
│ │ │ └── SidebarLink.vue
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ └── Layout.vue
│ │ └── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ ├── guide/
│ │ ├── README.md
│ │ ├── faq/
│ │ │ ├── how_to_reset.md
│ │ │ └── purchase.md
│ │ ├── technical/
│ │ │ ├── run_in_background.md
│ │ │ └── system_behaviors.md
│ │ └── working_mode/
│ │ ├── dpm.md
│ │ └── shizuku.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── changelog.md
│ │ ├── download.md
│ │ └── guide/
│ │ ├── README.md
│ │ ├── faq/
│ │ │ ├── how_to_reset.md
│ │ │ └── purchase.md
│ │ ├── technical/
│ │ │ ├── run_in_background.md
│ │ │ └── system_behaviors.md
│ │ └── working_mode/
│ │ ├── dpm.md
│ │ └── shizuku.md
│ └── zh-hant/
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ └── guide/
│ ├── README.md
│ ├── faq/
│ │ ├── how_to_reset.md
│ │ └── purchase.md
│ ├── technical/
│ │ ├── run_in_background.md
│ │ └── system_behaviors.md
│ └── working_mode/
│ ├── dpm.md
│ └── shizuku.md
├── assets/
│ └── SourceCodePro-BDC.css
├── package.json
├── shizuku/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ └── Layout.vue
│ │ └── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ ├── README.md
│ ├── download.md
│ ├── guide/
│ │ └── setup.md
│ ├── introduction.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── download.md
│ │ ├── guide/
│ │ │ └── setup.md
│ │ └── introduction.md
│ └── zh-hant/
│ ├── README.md
│ ├── download.md
│ ├── guide/
│ │ └── setup.md
│ └── introduction.md
├── storage_redirect/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── LICENSE
│ │ ├── components/
│ │ │ ├── AlgoliaSearchBox.vue
│ │ │ ├── Download.vue
│ │ │ ├── DropdownLink.vue
│ │ │ ├── DropdownTransition.vue
│ │ │ ├── Home.vue
│ │ │ ├── NavLink.vue
│ │ │ ├── NavLinks.vue
│ │ │ ├── Navbar.vue
│ │ │ ├── Page.vue
│ │ │ ├── PageEdit.vue
│ │ │ ├── PageNav.vue
│ │ │ ├── Sidebar.vue
│ │ │ ├── SidebarButton.vue
│ │ │ ├── SidebarGroup.vue
│ │ │ ├── SidebarLink.vue
│ │ │ └── SidebarLinks.vue
│ │ ├── global-components/
│ │ │ └── Badge.vue
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ ├── 404.vue
│ │ │ └── Layout.vue
│ │ ├── noopModule.js
│ │ ├── styles/
│ │ │ ├── arrow.styl
│ │ │ ├── code.styl
│ │ │ ├── config.styl
│ │ │ ├── custom-blocks.styl
│ │ │ ├── index.styl
│ │ │ ├── mobile.styl
│ │ │ ├── palette.styl
│ │ │ ├── toc.styl
│ │ │ └── wrapper.styl
│ │ └── util/
│ │ └── index.js
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ ├── guide/
│ │ ├── README.md
│ │ ├── advanced/
│ │ │ ├── shared_user_id.md
│ │ │ └── technical_details_export_isolated_files.md
│ │ ├── compatibility/
│ │ │ ├── README.md
│ │ │ ├── meizu.md
│ │ │ ├── miui.md
│ │ │ └── samsung.md
│ │ ├── contribute.md
│ │ ├── enhanced_mode/
│ │ │ ├── README.md
│ │ │ └── install.md
│ │ ├── faq/
│ │ │ ├── cant_find_app.md
│ │ │ ├── how_to_document.md
│ │ │ └── how_to_report_problems.md
│ │ └── tutorial.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── changelog.md
│ │ ├── download.md
│ │ └── guide/
│ │ ├── README.md
│ │ ├── advanced/
│ │ │ ├── shared_user_id.md
│ │ │ └── technical_details_export_isolated_files.md
│ │ ├── compatibility/
│ │ │ ├── README.md
│ │ │ ├── meizu.md
│ │ │ ├── miui.md
│ │ │ └── samsung.md
│ │ ├── contribute.md
│ │ ├── enhanced_mode/
│ │ │ ├── README.md
│ │ │ └── install.md
│ │ ├── faq/
│ │ │ ├── cant_find_app.md
│ │ │ ├── how_to_document.md
│ │ │ └── how_to_report_problems.md
│ │ └── tutorial.md
│ └── zh-hant/
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ └── guide/
│ ├── README.md
│ ├── advanced/
│ │ ├── shared_user_id.md
│ │ └── technical_details_export_isolated_files.md
│ ├── compatibility/
│ │ ├── README.md
│ │ ├── meizu.md
│ │ ├── miui.md
│ │ └── samsung.md
│ ├── contribute.md
│ ├── enhanced_mode/
│ │ ├── README.md
│ │ └── install.md
│ ├── faq/
│ │ ├── cant_find_app.md
│ │ ├── how_to_document.md
│ │ └── how_to_report_problems.md
│ └── tutorial.md
├── webhooks/
│ ├── .gitignore
│ ├── index.js
│ └── package.json
└── www/
├── .gitignore
├── .vuepress/
│ ├── config.js
│ ├── public/
│ │ └── robots.txt
│ └── theme/
│ ├── components/
│ │ ├── Home.vue
│ │ └── SidebarLink.vue
│ ├── index.js
│ ├── layouts/
│ │ └── Layout.vue
│ └── styles/
│ ├── index.styl
│ └── palette.styl
├── README.md
├── contribute_translation.md
├── knowledge/
│ ├── exit_on_start.md
│ └── google_play_purchase.md
├── privacy_policy.md
├── zh-hans/
│ ├── README.md
│ ├── contribute_translation.md
│ └── knowledge/
│ ├── exit_on_start.md
│ └── google_play_purchase.md
└── zh-hant/
├── README.md
├── contribute_translation.md
└── knowledge/
├── exit_on_start.md
└── google_play_purchase.md
================================================
FILE CONTENTS
================================================
================================================
FILE: .gitattributes
================================================
* text=auto
*.sh text eol=lf
hooks/* text eol=lf
*.png binary
*.ico binary
*.woff binary
*.woff2 binary
================================================
FILE: .github/dependabot.yml
================================================
version: 2
updates:
# Maintain dependencies for GitHub Actions
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
# Maintain dependencies for npm
- package-ecosystem: "npm"
directory: "/"
schedule:
interval: "daily"
================================================
FILE: .gitignore
================================================
/.vscode
/node_modules
/yarn.lock
================================================
FILE: appops/.gitignore
================================================
/.vuepress/dist
================================================
FILE: appops/.vuepress/config.js
================================================
const moment = require('moment')
const langMap = {
"zh-Hans": "zh-cn",
"zh-Hant": "zh-tw"
}
var timestampCache = {}
module.exports = {
base: '/',
title: 'App Ops',
head: [
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],
['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],
['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],
['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],
['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],
['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],
['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],
['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],
['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],
['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],
['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],
['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],
['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]
],
locales: {
'/': {
lang: 'en',
description: 'Control the hidden appops conveniently'
},
'/zh-hans/': {
lang: 'zh-Hans',
description: '方便地控制隐藏的 appops'
},
'/zh-hant/': {
lang: 'zh-Hant',
description: '方便地控制隱藏的 appops'
}
},
themeConfig: {
locales: {
'/': {
selectText: 'Languages',
label: 'English',
serviceWorker: {
updatePopup: {
message: "New content is available.",
buttonText: "Refresh"
}
},
sidebar: getSidebar("/guide/", "Basic", "Working modes", "FAQ", "Technical details"),
nav: getNavbar('/', 'Guide', 'Download', 'Changelog', 'Rikka Apps'),
lastUpdated: 'Last Updated'
},
'/zh-hans/': {
selectText: '语言',
label: '简体中文',
editLinkText: '在 GitHub 上编辑此页',
serviceWorker: {
updatePopup: {
message: "发现新内容可用.",
buttonText: "刷新"
}
},
sidebar: getSidebar("/zh-hans/guide/", "基础", "工作模式", "FAQ", "技术细节"),
nav: getNavbar('/zh-hans/', '指南', '下载', 'Changelog', 'Rikka Apps'),
lastUpdated: '最后更新'
},
'/zh-hant/': {
selectText: '語言',
label: '繁體中文',
editLinkText: '在 GitHub 上編輯此頁',
serviceWorker: {
updatePopup: {
message: "發現新內容可用.",
buttonText: "重新整理"
}
},
sidebar: getSidebar("/zh-hant/guide/", "基礎", "工作模式", "FAQ", "技術細節"),
nav: getNavbar('/zh-hant/', '指南', '下載', 'Changelog', 'Rikka Apps'),
lastUpdated: '最後更新'
}
},
displayAllHeaders: true,
sidebarDepth: 2,
serviceWorker: {
updatePopup: true
},
docsRepo: 'https://github.com/RikkaApps/websites',
docsDir: 'appops',
editLinks: true
},
plugins: [
[
'sitemap',
{
hostname: 'https://appops.rikka.app',
exclude: ['/404.html'],
dateFormatter: (time) => {
timestampCache[time]
}
}
],
/*[
'redirect',
{
locales: true,
}
],*/
[
'clean-urls',
{
normalSuffix: '/',
indexSuffix: '/',
notFoundPath: '/404.html'
}
],
[
'@vuepress/last-updated',
{
transformer: (timestamp, lang) => {
var original = timestamp
moment.locale(langMap[lang])
var localized = moment(original).format('lll')
moment.locale('en')
var iso = moment(original).toISOString()
timestampCache[localized] = iso
return localized
}
}
]
]
}
function getSidebar(prefix, basicTitle, workingModeTitle, faqTitle, technicalDetailsTitle) {
var res = {}
res[prefix] = [
{
title: basicTitle,
collapsable: false,
sidebarDepth: 1,
children: [
''
]
},
{
title: workingModeTitle,
collapsable: false,
sidebarDepth: 1,
children: [
'working_mode/shizuku',
'working_mode/dpm',
]
},
{
title: faqTitle,
collapsable: false,
sidebarDepth: 0,
children: [
'faq/how_to_reset',
'faq/purchase',
]
},
{
title: technicalDetailsTitle,
collapsable: false,
sidebarDepth: 0,
children: [
'technical/system_behaviors',
'technical/run_in_background',
]
}
]
return res
}
function getNavbar(prefix, guide, download, changelog, allRikkaApps) {
return [
{ text: guide, link: `${prefix}guide/` },
{ text: download, link: `${prefix}download/` },
{ text: changelog, link: `${prefix}changelog/` },
{ text: allRikkaApps, link: `https://rikka.app${prefix}` },
]
}
================================================
FILE: appops/.vuepress/public/icon/browserconfig.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<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>
================================================
FILE: appops/.vuepress/public/icon/manifest.json
================================================
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
================================================
FILE: appops/.vuepress/theme/components/Home.vue
================================================
<template>
<main class="home" aria-labelledby="main-title">
<header class="hero">
<img
v-if="data.heroImage"
:src="$withBase(data.heroImage)"
:alt="data.heroAlt || 'hero'"
>
<h1 v-if="data.heroText !== null" id="main-title">{{ data.heroText || $title || 'Hello' }}</h1>
<p class="description">
{{ data.tagline || $description || 'Welcome to your VuePress site' }}
</p>
<div class="actions">
<div
class="action"
v-if="data.secondaryActionText && data.secondaryActionLink"
>
<NavLink
class="action-button secondary"
:item="secondaryActionLink"
/>
</div>
<div
class="action"
v-if="data.actionText && data.actionLink"
>
<NavLink
class="action-button"
:item="actionLink"
/>
</div>
</div>
</header>
<div
class="features"
v-if="data.features && data.features.length"
>
<div
class="feature"
v-for="(feature, index) in data.features"
:key="index"
>
<h2>{{ feature.title }}</h2>
<p>{{ feature.details }}</p>
</div>
</div>
<Content class="theme-default-content custom"/>
<div
class="footer"
v-if="data.footer"
>
{{ data.footer }}
</div>
</main>
</template>
<script>
import NavLink from '@parent-theme/components/NavLink.vue'
export default {
components: { NavLink },
computed: {
data () {
return this.$page.frontmatter
},
actionLink () {
return {
link: this.data.actionLink,
text: this.data.actionText
}
},
secondaryActionLink () {
return {
link: this.data.secondaryActionLink,
text: this.data.secondaryActionText
}
}
}
}
</script>
<style lang="stylus">
.home
padding $navbarHeight 2rem 0
max-width 960px
margin 0px auto
display block
.hero
text-align center
img
max-width: 100%
max-height 280px
display block
margin 3rem auto 1.5rem
h1
font-size 3rem
h1, .description, .actions
margin 1.8rem auto
.description
max-width 35rem
font-size 1.6rem
line-height 1.3
color lighten($textColor, 40%)
.action
margin 0.6rem
.actions
display flex
flex-wrap wrap
align-items flex-start
align-content stretch
justify-content center
.action-button
display inline-block
font-size 1.2rem
color #fff
background-color $accentColor
padding 0.8rem 1.6rem
border-radius 4px
transition background-color .1s ease
box-sizing border-box
border-bottom 1px solid darken($accentColor, 10%)
&:hover
background-color lighten($accentColor, 10%)
.secondary
color $textColor
background-color #fff
transition background-color .1s ease
border 1px solid darken($textColor, 10%)
&:hover
background-color lighten($textColor, 90%)
.features
border-top 1px solid $borderColor
padding 1.2rem 0
margin-top 2.5rem
display flex
flex-wrap wrap
align-items flex-start
align-content stretch
justify-content space-between
.feature
flex-grow 1
flex-basis 30%
max-width 30%
h2
font-size 1.4rem
font-weight 500
border-bottom none
padding-bottom 0
color lighten($textColor, 10%)
p
color lighten($textColor, 25%)
.footer
padding 2.5rem
border-top 1px solid $borderColor
text-align center
color lighten($textColor, 25%)
@media (max-width: $MQMobile)
.home
.features
flex-direction column
.feature
max-width 100%
padding 0 2.5rem
@media (max-width: $MQMobileNarrow)
.home
padding-left 1.5rem
padding-right 1.5rem
.hero
img
max-height 210px
margin 2rem auto 1.2rem
h1
font-size 2rem
h1, .description, .actions
margin 1.2rem auto
.description
font-size 1.2rem
.action-button
font-size 1rem
padding 0.6rem 1.2rem
.feature
h2
font-size 1.25rem
</style>
================================================
FILE: appops/.vuepress/theme/components/SidebarLink.vue
================================================
<script>
import { isActive, hashRE, groupHeaders } from '@parent-theme/util'
export default {
functional: true,
props: ['item', 'sidebarDepth'],
render (h,
{
parent: {
$page,
$site,
$route,
$themeConfig,
$themeLocaleConfig
},
props: {
item,
sidebarDepth
}
}) {
// use custom active class matching logic
// due to edge case of paths ending with / + hash
const selfActive = isActive($route, item.path)
// for sidebar: auto pages, a hash link should be active if one of its child
// matches
const active = item.type === 'auto'
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
: selfActive
const link = item.type === 'external'
? renderExternal(h, item.path, item.title || item.path)
: renderLink(h, item.path, item.title || item.path, active)
const maxDepth = [
$page.frontmatter.sidebarDepth,
sidebarDepth,
$themeLocaleConfig.sidebarDepth,
$themeConfig.sidebarDepth,
1
].find(depth => depth !== undefined);
const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
|| $themeConfig.displayAllHeaders
if (item.type === 'auto') {
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
const children = groupHeaders(item.headers)
return [link, renderChildren(h, children, item.path, $route, maxDepth)]
} else {
return link
}
}
}
function renderLink (h, to, text, active) {
return h('router-link', {
props: {
to,
activeClass: '',
exactActiveClass: ''
},
class: {
active,
'sidebar-link': true
}
}, text)
}
function renderChildren (h, children, path, route, maxDepth, depth = 1) {
if (!children || depth > maxDepth) return null
return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
const active = isActive(route, path + '#' + c.slug)
return h('li', { class: 'sidebar-sub-header' }, [
renderLink(h, path + '#' + c.slug, c.title, active),
renderChildren(h, c.children, path, route, maxDepth, depth + 1)
])
}))
}
function renderExternal (h, to, text) {
return h('a', {
attrs: {
href: to,
target: '_blank',
rel: 'noopener noreferrer'
},
class: {
'sidebar-link': true
}
}, [text, h('OutboundLink')])
}
</script>
<style lang="stylus">
.sidebar .sidebar-sub-headers
padding-left 1rem
font-size 0.95em
a.sidebar-link
font-size 1em
font-weight 400
display inline-block
color $textColor
border-left 0.25rem solid transparent
padding 0.35rem 1rem 0.35rem 1.25rem
line-height 1.4
width: 100%
box-sizing: border-box
&:hover
color $accentColor
&.active
font-weight 600
color $accentColor
border-left-color $accentColor
.sidebar-group &
padding-left 2rem
.sidebar-sub-headers &
padding-top 0.25rem
padding-bottom 0.25rem
border-left none
&.active
font-weight 500
</style>
================================================
FILE: appops/.vuepress/theme/index.js
================================================
module.exports = {
extend: '@vuepress/theme-default'
}
================================================
FILE: appops/.vuepress/theme/layouts/Layout.vue
================================================
<template>
<ParentLayout/>
</template>
<script>
import ParentLayout from '@parent-theme/layouts/Layout.vue'
export default {
components: {
ParentLayout
}
}
</script>
================================================
FILE: appops/.vuepress/theme/styles/index.styl
================================================
code
overflow: auto
word-wrap:break-word
body
font-family Roboto, sans-serif
body:lang(zh-hans)
font-family Roboto, 'Noto Sans SC', sans-serif
body:lang(zh-hant)
font-family Roboto, 'Noto Sans TC', sans-serif
================================================
FILE: appops/.vuepress/theme/styles/palette.styl
================================================
$accentColor = #1565c0
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34
================================================
FILE: appops/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: Download
actionLink: /download.html
secondaryActionText: Learn more
secondaryActionLink: /guide/
features:
- title: Access hidden permission mechanism
details: Control permissions (partial) by modifying hidden appops settings with App Ops.
- title: Excellent user experience
details: Provides a beautiful and friendly user interface. App Ops does a lot of effort in many places to reduce the difficulty of use.
- title: Works without root
details: Provides a variety of working modes that only require adb.
- title: Follow the latest Android system
details: Support features from newer Android version, even the beta version will be supported in a few days.
- title: Detailed help
details: Provide detailed help documents.
- title: Provides advanced features
details: Easy to use with features such as templates, backup and recover.
footer: Copyright © 2019 RikkaApps
---
================================================
FILE: appops/changelog.md
================================================
# Changelog
## 9.0.6 (2023-08-03)
- Upgrade Shizuku to 13.5.0+ could solve the problem that automatic functions not work
- Fix the problem of "Unable to start service" on some realme devices
- Fix crash on pre-Android 7.1
## 9.0.0 (2023-04-08)
- 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
- Support for Android 14 (however, based on experience, the app will most likely not work again due to later changes)
- Hide `OP_TOAST_WINDOW` on Android 11+ for apps targeting API 30+ as it no longer works
- 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)
- Added option to allow backup of system components
- For Chinese, Japanese and Korean language users, if the system does not provide a Medium (500) weight font, it will use the simulation implementation
- Added prompt information for `com.android.externalstorage`, `com.android.providers.downloads`, `com.samsung.android.providers.media` not having permissions on Samsung devices
## 8.0.1 (2022-11-22)
- Allow backup without purchasing (restore the backup still need purchasing)
- Fix swithing user not working randomly
## 8.0.0 (2022-09-02)
- Experimental feature for Android 12 +: Usage history
- Adapt Android 12 to changes in location permissions
- Material Design 3
- Device admin mode removed due to Google Play policy changes
## 5.5.6 (2022-06-10)
- Works on Android 13 Beta 3
- Fix crash under French language
- Device Admin mode will be removed due to new Google Play policy changes
## 5.5.2 (2022-03-10)
- Replace the app icon because the old one "violates Google Play policies"
## 5.5.0 (2022-03-03)
- 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)
## 5.4.3 (2021-06-13)
- Fix the problem that "Automatic recovery" could cause all permissions in the same group be reset to "Ignore"
## 5.4.2 (2021-06-01)
- Fix backup is broken from version 5.4.0
- Fix some visual problem on old systems
## 5.4.0 (2021-05-27)
- Fix Clipboard monitor does not work on Android 12 Beta 1
- Fix "Ignore" cannot be set for apps in work profiles on Android 11+ (This fix is only possible under Shizuku mode)
- Hide `OP_QUERY_ALL_PACKAGES` since this op does nothing
- Hide `OP_NO_ISOLATED_STORAGE` since this op is only for debugging use
## 5.3.3 (2021-05-04)
- Adapt another Android 12 changes
- Prevent 💩 MIUI's "Force dark mode" from breaking app's theme<sup>**〔1〕**</sup>
<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>
## 5.3.1 (2021-04-03)
- Fix a problem that would cause the crash
- Adapt some Android 12 changes
## 5.3.0 (2021-01-28)
- The first step of correctly handling Shared user ID
## 5.2.0 (2021-01-16)
- Support Sui (https://github.com/RikkaApps/Sui)
## 5.1.3 (2020-11-29)
- Adapt changes of "Storage Isolation" v5
- Fix a problem that the backup will be broken if the system returns "wrong" data (exiting broken backups cannot be fixed)
## 5.1.2 (2020-10-07)
- Fix a problem related to creating backup
- Fix a problem related to "Clipboard monitor"
- Fix the problem that records for "Automatic recovery" sometimes may not be updated correctly
- Import translation from users
## 5.1.0 (2020-09-24)
- 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)
- Add search for "Permissions view"
## 5.0.6 (2020-09-06)
- Fix a problem related to creating backup
- Fix a problem related to batch operations (including using templates, backups, etc.)
- Import translation from users
- Other minor changes
## 5.0.4 (2020-08-30)
- Fix the problem that "Restoring backup" may be displayed when nothing is actually restored
- Import translation from users
- Other minor changes
## 5.0.3 (2020-08-27)
- Fix problem introduced in 5.0.2 (1236)
## 5.0.2 (2020-08-26)
- "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)
- Fix the problem that, under Delegated Device Admin mode, things available from Island 5.0+ is accidentally requested on all versions
- Fix the problem that the ignore option of "Automatic recovery" not actually works
- Fix the problem that, `RUN_IN_BACKGROUND` in the template is not correctly displayed after editing
## 5.0.1 (2020-08-24)
- Fix the problem that in the last version, admin apps using DSM API v3 are incorrectly marked as "missing support"
- Fix the problem that in the last version, not all options are displayed correctly in "Template"
- Fix the problem that in the last version, automatic backup restore function for frozen applications (based on "hide") is broken
- Reset package mode when necessary (for "incorrect" settings leaved by older App Ops or other appops tools that haven't adapt system changes correctly)
- Import user translations
## 5.0.0 (2020-08-22)
This 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).
This contains a lot of work behind, please read [technical details](./guide/technical/system_behaviors/).
**What you should to know:**
- What you see or change in App Ops now reflects the final status
- "Deny" in older versions is renamed to "Ignore"
- Old backups are no longer supported because they lack the necessary information (they may even contain wrong information)
- For Delegated Device Admin mode, currently, only Island v5.0+ has the support of new required APIs
- 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)
Other changes:
- Template: any options can be used in the template
- Backup: more flexibility when restoring
- Usage monitor: attempt to reduce "wrong" reports (sometimes the systems always reports app is using "location" even if the app is not running)
- Usage monitor & Clipboard monitor: add "exclude system apps" option
## 4.2.3 (2020-07-18)
- Add Turkish translation
- "Usage monitor" fix
## 4.2.2 (2020-07-16)
- Solved the problem of small probability of random stop from v4.0.0
- "Usage monitor" improvements
- Rearrange strings, anyone can participate in translation
## 4.2.0 (2020-07-12)
- Add "Usage monitor" (Requires Android 9+ & Shizuku starts via root)
Get notified when apps are using location, camera or microphone
## 4.1.1 (2020-07-10)
- Clipboard monitor: temporary access time is now optionable
- Clipboard monitor: fix a UI issue of "Excluded apps"
- Fix the problem that on Android 10+, the backup created after v4.0.0 may be broken
- Correctly report the error from DPM mode
- Temporarily not to use resource optimization feature from AAPT2, maybe this could solve the problem of random settings crash happens on some users
## 4.1.0 (2020-07-09)
- Clipboard monitor: add "Window position" and "Excluded apps" option
- Fix the problem that once the main process is dead, "New app behavior" will stop working
- Fix the problem for permission view, ui is not refreshed correctly
## 4.0.1 (2020-07-05)
- Fix the problem that in some situations, the monitor service is started abnormally
## 4.0.0 (2020-07-04)
Rewrite (partly) the app with latest technologies. The full rewrite with more improvements and new features will come in the near future.
- New feature: Clipboard monitor (Requires Android 10+ and Shizuku started with root)<sup>**〔1〕**</sup>
- Works on Android 10 & 11
- UI refresh
- Fix a problem related to restoring backup
- Always use built-in names<sup>**〔2〕**</sup>
- For free version, remove Google Ads (Promote our apps instead)
- For crash report, use AppCenter to replace Firebase Crashlytics (Also, crash report can be disabled)
- Target API 30
- Drop support for system plugin mode
- Drop support for Android 6.0
- Drop support for ask mode from old LineageOS based ROMs<sup>**〔3〕**</sup>
<sub><b>〔1〕</b>Exclude apps from the monitor will come in the next version</sub>
<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>
<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>
## 3.1.1 (2019-08-03)
- Fix can't modify template
## 3.1.0 (2019-08-02)
- Provide more obvious warnings when doing operations on system apps
- Provide edit & add for apply template dialog
- Fix the problem that it will always determine that you are using Island once you have used Island in Delegated Device admin mode
## 3.0.3 (2019-07-29)
- Minor bug fix
- Provide new website with document: <https://appops.rikka.app/>
## 3.0.2
- Fix Delegated Device admin is broken
- Fix wrong dependency
## 3.0.0
- Delegated Device admin mode: Fix app installation may not triggered when using Island
- (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)
- Template: check "Skip check" for default
- Template: improve edit UI
- Show prompt if an op is not included in stock Android
- Other bug fixes & UI improve
## 2.9.9
- Delegated Device admin mode: Fix some bugs related to Island support
- Privilege mode: Fix legacy Shizuku is always required
- Show all working modes (explains the reason if not support)
## 2.9.8
- (Experimental) Delegated Device admin mode support "God mode" of Island app (com.oasisfeng.island)
- Privilege mode: Fix "adb permission limited" prompt never shows (mainly for MIUI)
## 2.9.7
- Try to fix "Code 5"
## 2.9.5
- 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)
- Fix "Code 5 debug message: null" (by upgrading lib from Google :(
- Minor UI tweaks
## 2.9.4
- Target 29
- Fix bugs in 2.9.2
## 2.9.2
- Fix template is lost after upgrading to 2.9.1
- Notification language should follow app language setting perfectly
## 2.9.1
- Add Delegated Device admin mode (use API from supported Device admin app)
- Fix some bugs
- Include templates to backup
## 2.8.2
- Fix root mode not work on Android Q beta 3
- Fix a few features on older versions of Android may not work properly
- Fix "Show framework apps" option not work under root mode
- Fix overlay packages are not filtered under root mode
## 2.8.1
- Works on Android Q beta 3 (unable to see usage time now)
- Storage options not work on Q beta 3, it's a system bug
- Temporarily hide "Storage sandbox" option for Q beta AlipayPaymentDialogFragment3 (disable by default unless app declared, how to force enable is not clear)
- Update translation
- Set first template as default when not set (to save user who never read prompt text)
## 2.8.0
- Support new ops added from Android Q
- UI improve
## 2.7.0
- No more "Restart app required" on Android 9
- No more random error when use privilege mode (require upgrade to Shizuku v3 and force stop App Ops)
## 2.6.4
- Update translation
- Bug fix
## 2.6.3
- Update translation
- Bug fix
## 2.6.2
- Multi-user support for root mode (experimental)
- Add "Disabled first" for grouping by permissions list
- Improved "run in background" control UI for Android 9
- Bug fix
## 2.5.10
- Add help for Android 9
- Bug fix
## 2.5.9
- Fix bug related to multi-user
- Update pt-BR translation
## 2.5.8
- Fix bug
## 2.5.7
- Simplify detail UI
- Fix some ops can't be changed if this permission related to its'
opToSwitch's is not requested
## 2.5.5
- Fix process when first time using privileged mode on not rooted Android 9
- Fix the problem about losing unsaved data while editing template after screen rotation
- Press back to ask whether to save when editing template
- Fix crash when press enter in template name
- Hide unknown ops by default
- Update ru translation
## 2.5.3
- Fix bugs about new app monitor feature
- Try to fix crash when open app on users
## 2.5.2
- Fix system plugin mode is broken in 2.5.0
- Fix error information is not correctly displayed
- Fix not work on Android 7.x
- Fix the problem that "You have already own this item" happens on some Google Play users
- To make New app monitor feature more reliable, it requires foreground service now (only Android 8.0+),
but you can disable notification or set it to lowest importance to avoid being disturbed
## 2.5.0
- Remove System plugin for Android 9+
(because the plugin could work only if it is signed with the system signature)
- Simplify system plugin installation, provide zip download only
- Support appops features added from Android 9 (such as MODE_FOREGROUND & OP_RUN_ANY_IN_BACKGROUND)
- New UI
- Multi templates
- Solve the problem that unable to use if back to app after a long time
## 2.4.1
- Update translation
- Try to fix the problem that some paid users may be treated as unpaid
## 2.4.0
- Increase the speed of root mode
## 2.3.13
- May fix root mode not work on some devices
- Change icon for Android 8+
## 2.3.12
- Try fix crash when restore backup
## 2.3.11
- Add select all for all list (long press item -> 3-dot menu -> select all)
- System plugin mode now provides Magisk module template v1500 for Magisk users
## 2.3.10
- Fix crash when restore large number of backups
- Fix tip dialog content is not scrollable
## 2.3.9
- 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)
## 2.3.8
- Add "Show all modes" option (do not enable it if don't know what it is)
## 2.3.7
- _Always-shown permission (operation)_ will exclude some impossible situation
- Add error tip when App Ops in installed to external storage
- Update Portuguese (Brazil) translation
- Remove some unused resources
- Fix create backup is broken
## 2.3.6
- Fix "Google play not available"
- Add a list which displays all supported permissions (operation)
- Mark system app in app list
- Add _always-shown permission (operation)_ list, selected permissions will be treated may be used by all apps
- Settings UI tweak
## 2.3.5
- Fix backup preview is broken
- Add tip when local network (required by privileged mode) is limited
- Handle some uncaught error
## 2.3.4
- Fix reset is broken in root mode
- Fix reset or apply template from app list not refresh the UI
## 2.3.3
- Fix two old bug
## 2.3.2
- Fix bug in 2.3.0
- Asynchronous load other information (such as modified item count), so the app list loading process should be very fast now
## 2.3.0
- Add modified item count for app list
- Accelerate the process of fetching appops configuration when use root mode
- New Oreo-styled app detail view
- Support Android 8.1's light navigation bar
- Modify some confusing UI
- (Free users) Use old banner ads since Google will remove native express ads after March 2018
- Fix some multi-user related problems
- (Paid users) Fix a problem which related to auto backup restore
- Remove support for old Shizuku (privileged mode) due to some reason
## 2.2.6
- Fix unable to use when install Shizuku Manager later than open App Ops
## 2.2.5
- Add start on boot for new app monitoring
- Add Portuguese (Brazil) language
## 2.2.4
- Add a tip for the situation that adb only have get but no update appops configuration permission (most likely happened on MIUI ROM)
- Use new version build tool to avoid ([a terrible problem](https://issuetracker.google.com/issues/64434571)) on some custom ROM
## 2.2.3
- Fix possible crash when use _Privileged mode_ with old _Shizuku Manager_
- Do not check whether there is `RUN_IN_BACKGROUND` when applying template from notification
- Fix settings crash when switch work mode
## 2.2.2
- Fix crash when _Privileged mode_ is selected but _Shizuku Manager_ is not installed
## 2.2.1
- Add a feature that can change UI language
- Update translation
- Filter overlay apps by reflect `PackageInfo#overlayTarget`
- Fix action in new app notification may not work on some device
- Do not check whether there is `RUN_IN_BACKGROUND` when applying template
## 2.2.0
- Fix notification can't be dismissed after apply template or restore backup
- Reschedule main menu items
- Move "Show framework apps" to main menu
- Add "Sort by update time", "Sort by installation time"
- Lab add "Show target 0 apps" (for filter substratum overlay)
- Refactor setup wizard, also add more explanation
- Adjust settings UI
- Fix notification can't show adaptive icon (8.0+)
## 2.1.12 (beta)
- Temporarily query less data when fetching app list
> This will solve the problem that only part of app list is fetched (or even "Package Manager has died")
on some devices.
> Also makes the fetching progress faster.
> But without removed data, we have to remove "show apps without icon" option because we can't know
if the app have a entrance, and "run in background" (Android 7.0+) will always shown because we can't
speculated if the app have background behavior.
- (Privileged mode) Let Shizuku manager show user server is not running
- New version name rule
- Adapt Font Provider API v8
## 2.1.11
- Fix system plugin broadcast does not work
- Fix notification didn't show when plugin stopped
- Improve Settings UI for RTL language
- Introduce Shizuku v2 (privileged mode) for test, join test of Shizuku Manager if you want a try
- Font Provider (medium font weight for CJK language) is enabled by default
## 2.1.10
- Add a more friendly tip when system plugin don't have enough permission
- Try again to fix manual refresh is sometimes required when use system plugin
- Update Font Provider (for CJK language users) dependency to 1.3.2
- Add more help
- Fix some dialog's button color
## 2.1.9
- Fix NPE in WorkService
- Move system plugin download to GitHub release
- Fix crash when open help in runtime permission tip dialog
- Notify list refresh when system plugin connected
- Update translation
- Add translator's name to about
## 2.1.2 - 2.1.8
- Fix can't create backup file
- The entrance of Lab (including undetermined and experimental features) is now always enabled
- Provide fastScroll drawable from AOSP to avoid crash on some devices
- Update help
- Fix test link in pro version
- 100% fix theme and night mode, it should work perfectly now
- Update adaptive icon for Android O
- Add tip of Runtime Permissions when entering app target 23+
- Improved theme
- Add an option to use "Noto Sans CJK Medium" font from Font Provider app to replace "sans-serif-medium"
- Add tip for users can't use system plugin on Android O
## 2.1.1
- Enhanced backup (PRO)
- 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).
- Add detailed changelog
- New detailed help
================================================
FILE: appops/download.md
================================================
# Download
[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)
[Coolapk](https://www.coolapk.com/apk/rikka.appops)
[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)
================================================
FILE: appops/guide/README.md
================================================
# Learn App Ops
In short, **App Ops** is an app that **modifies the settings of "appops" in Android system**.
## What is "appops" in Android?
There 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").
Stock 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>.
However, the stock Android system does not provide a user interface that modifies the "appops" settings.
<sub>**\[1\]** App Ops app actually shows "Ignore" as "Deny"</sub>
<br><sub>**\[2\]** The actual behavior depends on the system, and the app can also check if "appops" is denied</sub>
## What is App Ops app?
The 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.
## Term
### "Permissions"
App 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.
::: tip
We still call it "permission" in the rest of the help
:::
## Limitations of App Ops
### Permissions can be modified are depend on your system
The permissions that App Ops can modify **depend only on your system**, so stop asking "why there is no XXX permission".
In 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.
### Apps can still check if they have no permission
Apps can check if the returned data is blank or directly check if "appops" is allowed. But there are very few apps do this.
================================================
FILE: appops/guide/faq/how_to_reset.md
================================================
# How to reset all settings?
1. Switch to app list mode
2. Long press or tap the app icon on the left to enter multi-select mode
3. Three-dot menu - Select all
4. Select "Reset"
================================================
FILE: appops/guide/faq/purchase.md
================================================
# Purchase or restore problems
## Google Play restore
In most cases, follow the prompts that appear after clicking the purchase. If you still can't solve the problem, please send us an email.
================================================
FILE: appops/guide/technical/run_in_background.md
================================================
# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND` (Run in background)
"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.
This article will explain the effect of modifying `RUN_IN_BACKGROUND` and `RUN_ANY_IN_BACKGROUND` on app behavior on Android 9.
## Special handling by the app App Ops
In 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.
## `RUN_IN_BACKGROUND`
> The article has not been completed, more information will be added later
All apps targeting API 26 and above will always subject to this restriction.
Refer to the following article:
Https://developer.android.com/about/versions/oreo/background
## `RUN_ANY_IN_BACKGROUND`
> The article has not been completed, more information will be added later
Refer to the following article:
Https://developer.android.com/about/versions/pie/power#battery-saver
Https://developer.android.com/topic/performance/power/power-details
Some of the commits involved:
Https://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18
Https://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16
================================================
FILE: appops/guide/technical/system_behaviors.md
================================================
# Difference under different Android versions
Each 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.
The following forms shows how the `uid mode` will be set when the permission settings are modified from the system.
::: details Forms
<p>
The asterisk (*) indicates changes from the previous system.
#### Android 6 - Android 9
| System setting page | uid mode |
|---------------------|-----------------------------------------|
| Allow | allow |
| Deny | ignore<br>(only for apps target pre-23) |
| (Not yet set) | (allow) |
#### Android 10
| System setting page | uid mode |
|--------------------------|------------|
| Allow only while using * | foreground |
| Allow | allow |
| Deny * | ignore |
| (Not yet set) | (allow) |
#### Android 11
| System setting page | uid mode |
|--------------------------|------------|
| Ask every time * | ignore |
| Allow only while using * | foreground |
| Allow | allow |
| Deny | ignore |
| (Not yet set) * | ignore |
#### Other behaviors on Android 11
* Setting `package mode` is invalid
* When setting `uid mode`, it is invalid if the set value does not match to the runtime permission status
* Under certain circumstances (for example, install an app), the system will reset the appops of **all apps** to states that match runtime permissions
:::
### The old version of App Ops didn't do it right
The old versions of App Ops (before v5.0.0) will only read and modify `package mode`, which is obviously wrong.
In 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).
Since 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.
### Changes made in the new version (v5.0.0) of App Ops
There is no choice but to follow the behavior of the system completely.
In 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.
### The new version (v5.0.0) App Ops needs more capabilities
To 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.
| | Shizuku mode | Delegated Device Admin mode | root mode (removed) |
|--------------------|--------------|--------------------------------|---------------------|
| appops | ✔️ | ✔️ | ✔️ |
| runtime permission | ✔️ | "Set" only<sup>**〔1〕**</sup> | ❌ |
| permission flags | ✔️ | ❌ | ❌ |
<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>
#### Defects of "Delegated Device Admin mode"
* "Unable to confirm"
* Cannot backup all settings
* In Android 11, the new "Ask every time" cannot be set (requires "set permission flags")
::: details Technical information
Administrator 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.
* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)
* [Delegation API](https://island.oasisfeng.com/api)
Only Island v5.0+ that provides Delegation API supports "set runtime permission".
For "unable to confirm", for example, in Android 10:
| | appops | runtime permission | permission flags |
|---------------|--------|--------------------|------------------|
| Ignore | ignore | true | |
| Deny | (any) | false | any "FIXED" flag |
| (Not yet set) | (any) | false | no "FIXED" flag |
Just looking at the appops setting is obviously not enough.
:::
#### Why "root mode" has to be removed?
The 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).
Therefore, the root mode has been removed.
::: details Technical information
Many 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.
The 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.
:::
================================================
FILE: appops/guide/working_mode/dpm.md
================================================
# Delegated Device Admin mode
::: warning Warning
As 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).
:::
## Requirements and Features
* Requires Android 9+
* Need to install other apps and use adb to set it as Device owner
* Multi-user support depends on the Device owner app
## Background
Delegated 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.
From v2.9.0, App Ops supports Device admin apps using [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager).
From v2.9.8, App Ops supports [another API provided by Island app](https://island.oasisfeng.com/api).
## Disclaimer
The Device admin app you need to install is not developed by us.
::: warning
Device 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.
:::
::: danger
Samsung 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**.
:::
## How to use
The setup process requires a computer to be use adb, but only needs to be set once.
### 1. Install and set up the Device admin app
#### IceBox
1. 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)
2. See [Help](https://iceboxdoc.catchingnow.com/Device%20Owner%20(Non%20Root)%20Setup) to set up Device admin mode for it
#### 小黑屋 (Simplified Chinese only)
1. Download from [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) or [Coolapk](https://www.coolapk.com/apk/web1n.stopapp )
2. 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
#### Island
1. 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)
2. See [Help](https://island.oasisfeng.com/setup.html) to set up Device admin mode for it (Island call it "God mode")
### 2. Granting permissions
In 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.
Next, you'll also need to grant App Ops the "get app ops" permission using adb. Use the following command:
```
adb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS
```
Note 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).
### 3. Granting multi-user permissions
For multi-user support, you also need to execute the following command to allow App Ops to partially access other users:
```
adb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS
```
::: tip
Currently only Island 3.8+ supports multiple users
:::
### 4. Have trouble?
* `Cannot request permission without a restrictions provider registered` when using Island
Clear cache of Island (App info -> Storage -> Clear cache) and restart Island.
================================================
FILE: appops/guide/working_mode/shizuku.md
================================================
# Shizuku mode
## Requirements and Features
* Need to install Shizuku app and start Shizuku service via adb or root
* Support multi-user
::: tip
If you use adb, you need to use adb to start Shizuku every time your device boot (**but the appops settings always take effect**)
:::
## Background
Shizuku 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.
> For information about Shizuku and the reason of making an application separately, please check [shizuku.rikka.app](https://shizuku.rikka.app/).
================================================
FILE: appops/zh-hans/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: 立即下载
actionLink: /zh-hans/download.html
secondaryActionText: 了解更多
secondaryActionLink: /zh-hans/guide/
features:
- title: 访问隐藏的权限机制
details: 借助 App Ops 修改隐藏的 appops 设置来(部分)控制权限。
- title: 优秀的用户体验
details: 提供美观、友好的用户界面。App Ops 在很多不为人知的地方做出许多努力以降低使用难度。
- title: 无需 root 也可使用
details: 提供多种只需 adb 的工作模式。
- title: 跟随最新的 Android 系统
details: 支持新版本 Android 的特性,即使是测试版系统也会在几天内得到支持。
- title: 详细的帮助
details: 提供详细的帮助文档。
- title: 提供高级功能
details: 借助模板、备份恢复等功能来方便操作。
footer: Copyright © 2019 RikkaApps
---
================================================
FILE: appops/zh-hans/changelog.md
================================================
# 变更日志
## 9.0.6 (2023-08-03)
- 升级 Shizuku 到 13.5.0 以上可能可以解决自动化功能不工作的问题
- 修复在部分 realme 设备上“无法启动服务”的问题
- 修复在 Android 7.1 及之前版本崩溃
## 9.0.0 (2023-04-08)
- 为 Android 10 及以上版本添加“传感器”权限,可控制应用是否可以使用加速度计、重力传感器等无需权限即可使用的传感器
- 支持 Android 14(但是,根据经验,应用程序很可能会因为之后的改动再次无法工作)
- 在 Android 11 以上针对目标 API 为 30 及以上的应用隐藏 `OP_TOAST_WINDOW`,因为其不再有效
- 在 Android 10 以上针对存储权限添加说明,因为系统允许特定的应用写入标准文件夹,即使其没有存储权限(特定的应用是指目标 API 是 30 或以上,或者目标 API 是 29 且适配了分区存储的应用)
- 增加允许备份系统组件的选项
- 针对中日韩语言用户,如果系统没有提供 Medium(500)字重的字体,则会使用模拟实现
- 针对在三星设备上出现的 `com.android.externalstorage`、`com.android.providers.downloads`、`com.samsung.android.providers.media` 无权限问题增加提示信息
## 8.0.1 (2022-11-22)
- 未解锁完整版时允许备份(恢复备份仍需要完整版)
- 修复切换用户随机失效
## 8.0.0 (2022-09-02)
- 针对 Android 12 及以上的实验性功能:使用情况历史
- 适配 Android 12 关于位置权限的变化
- Material Design 3
- 设备管理员模式因为 Google Play 政策变化而被移除
## 5.5.6 (2022-06-10)
- 在 Android 13 Beta 3 上工作
- 修复使用法语时崩溃的问题
- 设备管理员模式将要因为 Google Play 政策变化而被移除
## 5.5.2 (2022-03-10)
- 更换应用图标,因为旧图标“违反 Google Play 政策”
## 5.5.0 (2022-03-03)
- 在 Android 13 DP1 上工作(但是,根据经验,DP1 是非常早期的版本,应用程序很可能会因为 DP2 的改动再次无法工作)
## 5.4.3 (2021-06-13)
- 修复“自动恢复”可能造成所有同组权限都被重设为“忽略”的问题
## 5.4.2 (2021-06-01)
- 修复从 5.4.0 起备份坏掉
- 修复低版本系统上的一些视觉问题
## 5.4.0 (2021-05-27)
- 修复在 Android 12 Beta 1 上剪贴板监视器不工作的问题
- 修复在 Android 11 及以上版本,无法为安装在工作资料的应用设置“忽略”的问题(此修复只在 Shizuku 模式下可能)
- 隐藏 `OP_QUERY_ALL_PACKAGES` 因为完全没有用
- 隐藏 `OP_NO_ISOLATED_STORAGE` 因为它只用作调试
## 5.3.3 (2021-05-04)
- 适应另一个 Android 12 的改变
- 阻止 💩 MIUI 的“强制深色模式”弄坏自己的深色主题<sup>**〔1〕**</sup>
<sub><b>〔1〕</b>MIUI 有自己的“强制深色主题”,但是似乎即使应用正确地提供了深色主题,它也会继续起作用,从而把颜色改乱。</sub>
## 5.3.1 (2021-04-03)
- 修了一个可能导致崩溃的问题
- 适应一些 Android 12 的改变
## 5.3.0 (2021-01-28)
- 初步地加入正确处理 Shared user ID
## 5.2.0 (2021-01-16)
- 支持 Sui(https://github.com/RikkaApps/Sui)
## 5.1.3 (2020-11-29)
- 适应了“存储空间隔离” v5 的变化
- 修了如果系统返回了“错误”的数据备份会坏掉的问题(但是已经坏了的备份文件不可能修好)
## 5.1.2 (2020-10-07)
- 修复一个涉及创建备份的问题
- 修复一个涉及“剪贴板监视器”的问题
- 修复“自动恢复”的记录有时可能无法正确地被更新的问题
- 导入来自用户的翻译
## 5.1.0 (2020-09-24)
- “应用详情”及“权限视图”的批量操作现在可以使用所有的选项(注意,选中多个项目时,显示的选项为所有可用选项的交集)
- “权限视图”可以搜索
## 5.0.6 (2020-09-06)
- 修复一个有关创建备份的问题
- 修复一个有关批量操作(包括使用模板、备份等)的问题
- 导入来自用户的翻译
- 其他小改变
## 5.0.4 (2020-08-30)
- 修复了实际上未还原任何内容时“正在还原备份”也可能会显示的问题
- 导入来自用户的翻译
- 其他小改变
## 5.0.3 (2020-08-27)
- 修复 v5.0.2 (1236) 引入的问题
## 5.0.2 (2020-08-26)
- 为所有 Android 10 强制使用“自动恢复”选项,因为已确认 Android 10 也会进行重置(只是相较 Android 11 情况更少)
- 修复了在“托管设备管理员模式”下错误地要求所有版本的 Island 请求了只有 Island 5.0+ 提供的功能的问题
- 修复了“自动恢复”的忽略选项实际上不起作用的问题
- 修复了模板中的 `RUN_IN_BACKGROUND` 在编辑后没有正确显示的问题
## 5.0.1 (2020-08-24)
- 修了上个版本将使用 DSM API v3 的管理员应用错误地标明为“缺少支持”的问题
- 修了上个版本的模板并没有正确显示所有选项
- 修了上个版本针对(以“隐藏”为原理的)冻结类应用的自动恢复备份功能坏掉的问题
- 在必要时重设 package mode(针对使用旧版 App Ops 或其他尚未正确适应系统变化的 appops 工具留下的“错误”设置)
- 导入新增的用户翻译
## 5.0.0 (2020-08-22)
此更新解决了一个隐蔽但长期存在的问题。因为 Android 10 以下只在极少情况才出现,且升级到 Android 10 以后已有的设定不会被影响,这个问题在最近才浮出水面。一个典型的例子是,在 Android 10 中,一旦您从系统更改了位置权限,对旧版 App Ops 的更改将永远无法生效(即使看起来成功地更改了)。
这背后包含很多工作,请阅读[技术细节](./guide/technical/system_behaviors/)。
**您应该知道的内容:**
- 您在 App Ops 中看到或更改的内容现在反映最终状态
- 旧版本中的“拒绝”被重命名为“忽略”
- 不再支持旧备份,因为它们缺少必要的信息(甚至可能包含错误的信息)
- 对于“托管设备管理员模式”,当前只有 Island v5.0+ 支持新的必要的 API
- 对于“托管设备管理员模式”,备份的一部分来源于历史用户操作,这是因为管理员应用没有足够的权限来获取准确的状态(这是系统限制)
其他变化:
- 添加自动恢复功能:针对 Android 11 和部分高度修改的系统(MIUI,Oxygen 等)会自动复原设置的系统
- 模板:不止“忽略”(“拒绝”),现在可以在模板中使用任何选项
- 备份:还原时更加灵活
- 使用情况监控器:尝试减少“错误”报告(有时系统始终报告应用正在使用“位置”,即使该应用已经不再运行也是如此)
- 使用情况监控器 & 剪贴板监视器:加入“排除系统应用”选项
## 4.2.3 (2020-07-18)
- Add Turkish translation
- "Usage monitor" fix
## 4.2.2 (2020-07-16)
- 解决了从 v4.0.0 起出现的小概率随机停止运行问题
- “使用情况监视器”改进
- 重新整理字符串,任何人都可以参与翻译
## 4.2.0 (2020-07-12)
- 增加“使用情况监视器”(需要 Android 9 以上和通过 root 启动的 Shizuku)
当应用使用位置、相机或麦克风时收到提示
## 4.1.1 (2020-07-10)
- 剪贴板监视:可设定“临时访问时限”
- 剪贴板监视:修复一个有关“排除的应用”的 UI 问题
- 修复在 Android 10 以上,从 v4.0.0 起建立的备份可能损坏的问题
- 正确地回报来自托管设备管理员模式的错误
- 暂时不使用 AAPT2 的资源优化功能,这可能可以解决部分用户出现的随机的设置界面崩溃问题
## 4.1.0 (2020-07-09)
- 剪贴板监视:增加“窗口位置”和“排除的应用”选项
- 修复一旦主要进程死掉,“新应用行为”功能就会停止工作
- 修复权限视图 UI 刷新问题
## 4.0.1 (2020-07-05)
- 修复在某些情况下监视服务非正常地启动
## 4.0.0 (2020-07-04)
用最新技术(部分)重写。具有更多改进和新功能的全面重写将在不久的将来出现。
- 新功能:剪贴板监视(需要 Android 10 以上和通过 root 启动的 Shizuku)<sup>**〔1〕**</sup>
- 在 Android 10 及 11 上工作
- 用户界面翻新
- 修复一个有关恢复备份的问题
- 永远使用内置的名称<sup>**〔2〕**</sup>
- 对于免费版本,移除 Google Ads(转而推荐我们的其他应用)
- 对于崩溃报告,使用 AppCenter 替代 Firebase Crashlytics(此外,崩溃报告可关闭)
- 目标 API 30
- 不再支持系统插件模式
- 不再支持 Android 6.0
- 不再支持古老的以 LineageOS 为基础的 ROM 中的询问模式<sup>**〔3〕**</sup>
<sub><b>〔1〕</b>从监视中排除应用的功能将在下个版本中加入</sub>
<br><sub><b>〔2〕</b>之前,“权限”的名称被优先使用。但是随着 Android 在每个版本间不断改变权限名称,权限名称越来越不准确。</sub>
<br><sub><b>〔3〕</b>根据用户报告,一些老旧的三星设备表现得有这个功能,但是改为“询问”将会导致系统无法启动。</sub>
## 3.1.1 (2019-08-03)
- 修复无法编辑模板
## 3.1.0 (2019-08-02)
- 操作系统应用时提供更加明显的警告
- 为套用模板对话框提供编辑与添加功能
- 修复使用托管设备管理员模式时,如果先使用 Island 之后更换为其他也会被判定为正在使用 Island
## 3.0.3 (2019-07-29)
- 小 bug 修复
- 提供新的包含文档的网站:<https://appops.rikka.app/zh-hant>
## 3.0.2
- 修复托管设备管理员模式坏掉
- 修复错误的依赖
## 3.0.0
- 托管设备管理员模式:修复当使用 Island 时新应用安装可能不被出发
- (实验性)托管设备管理员模式:支持多用户(需要 Island 3.8+ 作为设备管理员,2019/7/24 在 Google Play alpha 通道提供)
- 模板:默认勾选“跳过检查”
- 模板:改进编辑 UI
- 如果一个 op 不被原生 Android 包含,显示提示
- 其他 bug 修复和 UI 改进
## 2.9.9
- 托管设备管理员模式:修复一些与 Island 支持有关的 bug
- 特权模式:修复总是需要旧式 Shizuku
- 显示所有工作模式(解释原因如果不支持)
## 2.9.8
- (实验性)托管设备管理员模式支持 Island 应用的“上帝模式” (com.oasisfeng.island)
- 特权模式:修复“adb 权限不足”提示从未显示(主要只给 MIUI)
## 2.9.7
- Try to fix "Code 5"
## 2.9.5
- 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)
- Fix "Code 5 debug message: null" (by upgrading lib from Google :(
- Minor UI tweaks
## 2.9.4
- Target 29
- 修 2.9.2 带来的 bug
## 2.9.2
- 修复升级到 2.9.1 后模板丢失
- 通知语言现在应该完美跟随应用内语言设置
## 2.9.1
- 增加托管设备管理员模式(使用来自支持的设备管理员应用的 API)
- 修一些 bug
- 备份包含模板
## 2.8.2
- 修复 root 模式在 Android Q beta 3 上不工作
- 修复在低版本 Android 上少数功能可能不正常
- 修复“显示框架应用”选项在 root 模式下不工作
- 修复 root 模式下 overlay package 们没有被过滤
## 2.8.1
- 在 Android Q beta 3 上能用(但还不能看使用时间)
- 存储空间选项在 Q beta 3 上无效,这是系统 bug
- 暂时在 Q beta 3 上隐藏“存储空间沙盒”选项(默认关闭除非应用声明,如何强制开启方法尚不明确)
- 当未设定默认模板时自动设定第一个(用于拯救从不阅读提示的傻子)
## 2.8.0
- 支持 Android Q 添加的新 op
- UI 改进
## 2.7.0
- 在 Android 9 上再也不会出现“需要重启应用”
- 使用特权模式时不再会出现随机错误(需要升级到 Shizuku v3 并强行停止 App Ops)
## 2.6.4
- 更新其他语言的翻译
- 修复 bug
## 2.6.3
- 更新其他语言的翻译
- 修复 bug
## 2.6.2
- root 模式支持多用户(实验性)
- 为根据权限分组的列表加入“已禁用有限”选项
- 为 Android 9 用户优化控制“在后台运行”时的 UI
- 修复 bug
## 2.5.10
- 增加为 Android 9 准备的帮助
- 修复 bug
## 2.5.9
- 修复一个涉及多用户的 bug
## 2.5.8
- 修复 bug
## 2.5.7
- 简化详情界面 UI
- 修复当一些 op 的 opToSwitch 所对应的权限没有申请时就无法更改那些 op 的 bug
## 2.5.5
- 修复无 root 在 Android 9 上首次使用特权模式的流程
- 修复编辑中的模板如果进行旋转屏幕等操作会丢失已编辑内容的问题
- 编辑模板按下返回会询问是否保存
- 修复在模板名称按下回车会爆炸
- 默认隐藏未知的 op(对,又是你 MIUI)
## 2.5.3
- 修复一些关于新应用监控的问题
- 可能修复一些打开就爆炸
## 2.5.2
- 修复在 2.5.0 中系统插件模式无法使用
- 修复错误信息没有被正确展示
- 修复在 Android 7.x 上无法正常工作
- 修复部分 Google Play 用户会出现“您已拥有此物品”的问题
- 为了让监控新应用安装功能更加可靠,现在它需要运行一个前台服务(仅 Android 8.0 以上),
但你可以禁用或将其设定为最低重要程度来避免被打扰
## 2.5.0
- 为 Android 9+ 移除系统插件(因为只有在插件拥有系统签名时才能工作)
- 简化系统插件安装,只提供 zip 下载
- 支持 Android 9 添加的 appops 特性(如 MODE_FOREGROUND 和 OP_RUN_ANY_IN_BACKGROUND)
- 新的 UI
- 多组模板
- 解决当长时间后返回, app 无法使用的问题
## 2.4.1
- 更新翻译
- 尝试修复部分付费用户会被当作未付费用户的问题
## 2.4.0
- 提升 root 模式速度
## 2.3.13
- 尝试修复 root 模式在部分设备无法工作
- 改变 Android 8+ 上的图标
## 2.3.12
- 尝试修复在恢复备份时可能崩溃
## 2.3.11
- 为所有列表添加全选(长按 -> 菜单里的三个点点 -> 全选)
- 系统插件模式现在为 Magisk 用户提供 template v1500 的模块
## 2.3.10
- 修复当恢复大量备份时崩溃
- 修复提示对话框内容不可以滚动的问题
## 2.3.9
- 修了在 Android P DP1 上崩溃(你可能会看到 "Detect problems with API compatibility" 的提示,但是对 App Ops 来说不使用隐藏 API 是不可能的)
## 2.3.8
- 增加“显示全部模式”选项(不懂是什么就别打开)
## 2.3.7
- _始终显示权限(操作)_ 将会排除一些绝对不可能的情况
- 增加被安装到外部存储的错误提示(都 8012 了怎么还有这种人)
- 更新葡萄牙语(巴西)翻译
- 移除一些未使用资源
- 修复创建备份坏掉
## 2.3.6
- 修了总是提示 Google play 不可用
- 增加一个显示全部支持的权限(操作)的列表
- 在应用列表中标记系统应用
- 增加 _始终显示的权限(操作)_ 列表,每个应用都会被当作可能使用选中的权限
- 调整设置 UI
## 2.3.5
- 修复备份预览坏掉
- 增加本地网络(特权模式需要使用)受限时的提示
- 处理一些未捕获的错误
## 2.3.4
- 修复 root 模式下重置无效的问题(真·上古 bug)
- 修复从应用列表重置或应用模板不会刷新 UI 的问题
## 2.3.3
- 修了两个上古 bug
## 2.3.2
- 修了 2.3.0 留下的 bug
- 异步读取其他信息(比如已修改的项数),因此现在读取应用列表速度会非常快
## 2.3.0
- 为应用列表增加已修改的项数
- 极大加速 root 模式下获取 appops 配置的速度
- Oreo 风格的应用详情视图
- 支持 Android 8.1 的亮色导航栏
- 修改一些令人疑惑的 UI
- (免费用户) 因为 Google 将在 2018 年 3 月后移除快捷原生广告,所以换回旧的横幅广告
- 修复一些和多用户有关的问题
- (付费用户) 修复在应用安装后,即使备份存在且打开了恢复备份,只要模板存在就被套用的问题
- 因为一些原因,移除对旧的 Shizuku (特权模式)的支持
## 2.2.6
- 修复 Shizuku Manager 比 App Ops 安装晚会无法使用的问题
## 2.2.5
- 为新应用监控添加开机启动
- 添加 Portuguese (Brazil) 语言
## 2.2.4
- 增加针对 adb 有读取 appops 配置但没有写入权限时的提示(比如 MIUI MIUI 和 MIUI)
- 使用新的 build tool 来避免一个只在部分低版本第三方 ROM 上出现的可怕的问题 ([看这里](https://issuetracker.google.com/issues/64434571))
## 2.2.3
- 修复_特权模式_使用旧版 _Shizuku Manager_ 可能会崩溃的问题
- 从通知套用模板时不再检查是否有 `RUN_IN_BACKGROUND`
- 修复切换工作模式时设置崩溃
## 2.2.2
- 修复选择_特权模式_时没有安装 _Shizuku Manager_ 会崩溃
## 2.2.1
- 增加指定界面语言的功能
- 更新翻译
- 通过反射 `PackageInfo#overlayTarget` 的方式过滤 overlay apps
- 修了新应用通知上的按钮在部分设备上可能不能用的问题
- 套用模板时不再检查是否有 `RUN_IN_BACKGROUND`
## 2.2.0
- 修复套用模板或恢复备份后通知不能消除的问题
- 重新规划主菜单项目
- 将“显示框架应用”移至主菜单
- 增加“根据更新时间排序”,“根据安装时间排序”
- 实验室增加 "Show target 0 apps" (为了过滤掉 substratum overlay)
- 重构设置向导,同时增加更多说明
- 调整设置 UI
- 修复通知不能显示自适应图标 (8.0+)
## 2.1.12 (beta)
- 在获取应用列表是请求更少数据
> 解决部分设备上只能获得部分应用(甚至出现 "Package Manager has died")的问题。
> 会加快列表刷新速度。
> 但没有那些数据,we have to remove "show apps without icon" option because we can't know
if the app have a entrance, and "run in background" (Android 7.0+) will always shown because we can't
speculated if the app have background behavior.
- (特权模式)让 Shizuku manager 展示服务没有运行
- 新的版本号明明规则
- 适配 Font Provider API v8
## 2.1.11
- Fix system plugin broadcast does not work
- Fix notification didn't show when plugin stopped
- Improve Settings UI for RTL language
- 引入 Shizuku v2 (特权模式),加入 Shizuku Manager 的测试来尝试
- Font Provider 默认开启
## 2.1.10
- 当系统插件权限不足时给用户更友好的提示
- 再次修复使用系统插件时有时需要手动刷新
- 更新 Font Provider 依赖到 1.3.2,应该没问题了
- 增加更多帮助
- 修了一些对话框的按钮颜色
## 2.1.9
- Fix NPE in WorkService
- Move system plugin download to GitHub release
- Fix crash when open help in runtime permission tip dialog
- Notify list refresh when system plugin connected
- Update translation
- Add translator's name to about
## 2.1.2 - 2.1.8
- 修复无法创建备份文件
- 实验室(包含未确定或实验性功能)功能入口现在总是显示
- Provide fastScroll drawable from AOSP to avoid crash on some devices
- Update help
- Fix test link in pro version
- 100% fix theme and night mode, it should work perfectly now
- Update adaptive icon for Android O
- Add tip of Runtime Permissions when entering app target 23+
- 改进的主题
- 提供一个新的选项来使用 "Noto Sans CJK Medium" 替换 "sans-serif-medium" 字体(需要配合 Font Provider 应用使用)
- Add tip for users can't use system plugin on Android O
## 2.1.1
- 增强的备份功能 (PRO)
- 当用户改变权限设置后,设置会被自动保存至数据库。当应用在卸载后再次安装或是被使用设备管理器的冻结类应用(如[冰箱](https://play.google.com/store/apps/details?id=com.catchingnow.icebox)的免 root模式)禁用后重新启用后可以选择恢复。
- 增加详细的更新日志
- 新的更详细的帮助
================================================
FILE: appops/zh-hans/download.md
================================================
# 下载
[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)
[Coolapk](https://www.coolapk.com/apk/rikka.appops)
[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)
================================================
FILE: appops/zh-hans/guide/README.md
================================================
# 了解 App Ops
简而言之,**App Ops** 是一个修改 **Android 系统中的 "appops" 设置** 的应用。
## 什么是 Android 系统中的 "appops"
在 Android 系统中存在一个叫做 "appops" 的系统服务,该服务定义了一系列的“应用操作”(application operation, op)。其中部分“应用操作”与“权限”对应(如 `OP_CAMERA` 与“相机权限”),其余则对应单独的功能(如 `OP_READ_CLIPBOARD` 与读取剪贴板,但并不存在“读取剪贴板权限”)。
原生 Android 系统使用 appops 来追踪权限使用,appops 也部分被用于权限控制。每个应用都有自己的 "appops" 设置,当应用需要执行某些操作时,系统在检查权限的同时也会检查 "appops" 设置。如果没有授予权限,应用在执行操作时将会收到错误。但不同的是,如果 "appops" 设为忽略<sup>**〔1〕**</sup>,应用不会收到错误只会收到空白数据<sup>**〔2〕**</sup>。
但是原生 Android 系统并没有提供修改 "appops" 设置的用户界面。
<sub>**〔1〕** App Ops 应用中实际将“忽略”显示为“拒绝”</sub>
<br><sub>**〔2〕** 实际行为取决于系统,应用也可检查 "appops" 是否被拒绝</sub>
## 什么是 App Ops 应用
App Ops 应用的核心功能是修改系统 "appops" 设置,可以在某种意义上实现权限管理。App Ops 应用还做出很多努力简化许多技术细节,让使用更加简单。
## 用语声明
### “权限”
App Ops 实际修改的是“应用操作”而非“权限”,但为了降低难度将其称为“权限”。App Ops 应用**不可以直接操作“权限”**,请不要误解。
::: tip
帮助中的其他地方仍称其为“权限”。
:::
## App Ops 的限制
### 可以修改的权限取决于系统
App Ops 所能修改的权限**只取决于你的系统**,所以别再问“为什么没有 XXX 权限”了。
通常,系统版本越高,能修改的内容越多(厂商或自定义 ROM 可能会添加自己的权限)。所有你的系统支持的权限可以在 设置 - 行为 - 全部权限 中看到。
### 应用仍可以获知没有权限
应用可以检查返回数据是否为空白,或是直接检查 "appops" 是否被允许。只是很少有应用这么做。
================================================
FILE: appops/zh-hans/guide/faq/how_to_reset.md
================================================
### 如何重置全部设置?
1. 切换到应用列表模式
2. 长按或点击左侧应用图标进入多选模式
3. 右上方三点菜单 - 全选
4. 选择“重置”
================================================
FILE: appops/zh-hans/guide/faq/purchase.md
================================================
# 购买或恢复问题
## Google Play 恢复问题
大部分情况下,按照点击购买后出现的提示文字处理即可,如果仍不能解决问题,请发送邮件给我们。
================================================
FILE: appops/zh-hans/guide/technical/run_in_background.md
================================================
# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`(在后台运行)
在 App Ops 应用中看到的“在后台运行”实际是指 `RUN_IN_BACKGROUND`(Android 7 起增加)和 `RUN_ANY_IN_BACKGROUND`(Android 9 起增加)这两个 op。在不同的系统版本上,改变这些 op 会有不同的行为。
这篇文章将会说明在 Android 9 上修改 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 对应用行为的影响。
## App Ops 应用所做的特殊处理
为了应对 Android 9 新增加的 `RUN_ANY_IN_BACKGROUND`,App Ops v2.6.0 以前采取这样的策略:直接将 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 视为同一个,即只会看到一个“在后台运行”选项,修改时会同时修改这两个。但部分特殊情况下,同时设置两个会造成限制过于严格的问题,因此从 v2.6.0 起可以自行选择限制哪一个。
## `RUN_IN_BACKGROUND`
> 文章尚未完成,更多信息将在以后补充
所有 target API 在 26 及以上的应用会受到此限制。
参考以下文章:
https://developer.android.com/about/versions/oreo/background
## `RUN_ANY_IN_BACKGROUND`
> 文章尚未完成,更多信息将在以后补充
参考以下文章:
https://developer.android.com/about/versions/pie/power#battery-saver
https://developer.android.com/topic/performance/power/power-details
部分涉及的 commit:
https://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18
https://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16
================================================
FILE: appops/zh-hans/guide/technical/system_behaviors.md
================================================
# 不同 Android 版本下的不同
每个 op 都有两种 mode,分别为 `package mode` 和 `uid mode`。`uid mode` **有更高优先级**,即只有当 `uid mode` 为默认值时才会使用 `package mode`。
以下表格展示了从系统修改权限设定时,`uid mode` 会被如何设定。
::: details 表格
<p>
星号(*)表示相对之前的系统放生变化。
#### Android 6 - Android 9
| 系统设定页面 | uid mode |
|--------------|-----------------------------------------|
| 允许 | allow |
| 拒绝 | ignore(只对 target 23 以下的应用设定) |
| (尚未设定) | (allow) |
#### Android 10
| 系统设定页面 | uid mode |
|--------------------|------------|
| 仅在使用期间允许 * | foreground |
| 允许 | allow |
| 拒绝 * | ignore |
| (尚未设定) | (allow) |
#### Android 11
| 系统设定页面 | uid mode |
|--------------------|------------|
| 每次都询问 * | ignore |
| 仅在使用期间允许 * | foreground |
| 允许 | allow |
| 拒绝 | ignore |
| (尚未设定)* | ignore |
#### Android 11 中的其他行为
* 设置 `package mode` 无效
* 设置 `uid mode` 时,若设定值不符合运行时权限状态则无效
* 在特定的情况下(比如安装应用后),系统将重设**全部应用**的 appops 设定到与运行时权限符合的状态
:::
### 旧版本 App Ops 没做对
旧版本的 App Ops(v5.0.0 以前)只会读取和修改 `package mode`,这显然是不对的。
在 Android 9 及之前,对 target 23 以下的应用在 App Ops 中设定“允许”是无效的;在 Android 10,一旦用户在系统中设置“拒绝”或“仅在使用时允许”,则在 App Ops 中的设置永远无法生效(因为此时系统设置的 `uid mode` 被优先使用)。
由于从低版本升级时系统的权限设定是被保留的,这个巨大的问题在 Android 10 发布的一年后才慢慢地暴露出来。
### 新版本(v5.0.0)App Ops 所做出的变化
除了完全跟随系统行为以外别无选择。
另外,因为 Android 11 会重置 appops 设定(所有“运行时权限允许,ops 忽略”会被重设为“运行时权限拒绝”),所以除了在系统之后再次重设以外别无选择。
### 新版本(v5.0.0)App Ops 需要更多能力
想要正确跟随系统行为,App Ops 必须具备取得和设置 `runtime permission`,`permission flags`,`appops` 的能力。但是,并不是所有工作模式都能做到。
| | Shizuku 模式 | 托管设备管理员模式 | root 模式(已被移除) |
|--------------------|--------------|------------------------------|-----------------------|
| appops | ✔️ | ✔️ | ✔️ |
| runtime permission | ✔️ | 仅可设置<sup>**〔1〕**</sup> | ❌ |
| permission flags | ✔️ | ❌ | ❌ |
<sub><b>〔1〕</b>需要 Island v5.0+ 或其他具有 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) v3 支持的管理员应用</sub>
#### “托管设备管理员模式”的缺陷
* “无法确认”
* 无法备份全部设置
* 在 Android 11,无法设定新增的“每次都询问”(需要“设置 permission flags”)
::: details 技术信息
被设为 `profile owner` 或 `device owner` 的管理员应用享有一些特权,但是只有它们自身可以使用。因此,不同的管理员应用提供了不同的 API,使其他应用得以“借用”其特权。
* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)
* [Delegation API](https://island.oasisfeng.com/api)
只有提供 Delegation API 的 Island v5.0+ 支持“设置 runtime permission”。
对于“无法确认”,举个例子,在 Android 10 中:
| | appops | runtime permission | permission flags |
|--------------|------------|--------------------|------------------|
| 忽略 | ignore | true | |
| 拒绝 | (任何值) | false | 任意 "FIXED" |
| (尚未设置) | (任何值) | false | 无 "FIXED" |
只看 appops 设置显然不够。
:::
#### 为什么必须移除“root 模式”
纯 root(执行指令)的能力十分有限,没有可以修改 permission flags 的指令。想要正确修改 runtime permission 必须保证 permission flags 也被正确地修改(设备管理员所使用的更高层级的 Java API 不需要考虑这个问题)。
因此,root 模式已被移除。
::: details 技术信息
很多人会认为 root 无所不能,但实际上 root 只提供了一个 `uid 0` 的 shell。想要进入 Android 世界(直接使用 Java API),通过 `app_process` 运行 dex 几乎是唯一选择。
“root 模式”的替代——“Shizuku 模式”使用 Shizuku([GitHub](https://github.com/RikkaApps/Shizuku))做这一部分的工作。如果不使用 Shizuku,则仍然需要运行类似 Shizuku 的东西,这样做是没有意义的,并且也将带来无意义的资源使用。
:::
================================================
FILE: appops/zh-hans/guide/working_mode/dpm.md
================================================
# 托管设备管理员模式
::: warning 警告
从 6.0.0 起,此工作模式不再支持。若要继续使用此工作模式,请[下载 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/download/files/appops-v5.5.6.r1453.f44c5855.apk)。
:::
## 需求及特性
* 需要 Android 9+
* 需要安装其他应用,并使用 adb 将其设为 Device owner
* 是否支持多用户取决于 Device owner 应用
## 背景
托管设备管理员模式是 App Ops 从 v2.9.0 开始加入的新的工作模式。从 Android 9 开始,设备管理员开始可以修改 appops 设定,但系统限制一台设备上仅能设置一个应用为设备管理员。因此 App Ops 使用由其他设备管理员应用提供的 API。
从 v2.9.0 起支持使用 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) 的设备管理员应用。
从 v2.9.8 起支持另一种[由 Island 提供的 API](https://island.oasisfeng.com/api)。
## 免责声明
你需要安装的设备管理员应用都不是由我们开发。
::: warning
设备管理员在三星设备及很多来自中国大陆地区厂商的设备上或多或少存在一些问题,请务必仔细阅读来自设备管理员应用提供的帮助,如果你无法接受可能的问题,请不要使用。
:::
::: danger
三星设备在使用设备管理员后可能造成无法挽回的结果(参阅 [来自 冰箱 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)),请务必谨慎。
:::
## 如何使用
设置过程需要连接电脑使用 adb,但只需要进行一次设置。
### 1. 安装及设置设备管理员应用
#### 冰箱 IceBox
1. 下载 [Google Play](https://play.google.com/store/apps/details?id=com.catchingnow.icebox) 或 [Coolapk](https://www.coolapk.com/apk/com.catchingnow.icebox)
2. 参阅 [帮助](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) 为其设置设备管理员模式
#### 小黑屋
1. 下载 [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) 或 [Coolapk](https://www.coolapk.com/apk/web1n.stopapp)
2. 参阅 [帮助](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)(仅提供简体中文) 为其设置设备管理员模式
#### Island
1. 下载 [Google Play](https://play.google.com/store/apps/details?id=com.oasisfeng.island) 或 [Coolapk](https://www.coolapk.com/apk/com.oasisfeng.island)
2. 参阅 [帮助](https://island.oasisfeng.com/setup.html) 为其设置设备管理员模式(Island 称其为“上帝模式”)
### 2. 授予权限
在 App Ops “设置”-“工作模式”中选择“托管设备管理员模式”后返回应用列表应该会弹出来自设备管理员应用的授权对话框,请在勾选“修改 app ops”后确认。
接着,你还需要使用使用 adb 授予 App Ops “获取 app ops” 权限。使用以下的指令:
```
adb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS
```
注意,如果你将 App Ops 应用安装到其他用户,需要将其中 `--user 0` 的 `0` 替换为其他用户的 id(使用 `adb shell pm list users` 获得的 `UserInfo{0:Owner:13} running` 的结果中的 `0` 即为用户 id)。
### 3. 授予多用户权限
对于多用户支持,你还需要运行下面的指令来让 App Ops 可以部分访问其他用户:
```
adb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS
```
::: tip
目前只有 Island 3.8+ 支持多用户
:::
### 4. 遇到问题?
* 使用 Island 时出现 `Cannot request permission without a restrictions provider registered`
清除 Island 的缓存(应用信息 -> 存储 -> 清除缓存),后重新启动 Island。
================================================
FILE: appops/zh-hans/guide/working_mode/shizuku.md
================================================
# Shizuku 模式
## 需求及特性
* 需要安装 Shizuku 应用并通过 adb 或 root 启动 Shizuku 服务
* 支持多用户
::: tip
如果使用 adb,每次开机都需要使用 adb 进行启动 Shizuku 的步骤(**但 appops 设置总是生效**)
:::
## 背景
Shizuku 是一个免费且[开源](https://github.com/RikkaApps/Shizuku)的类似于框架的应用。它旨在服务多个需要 root 或 adb 的应用。Shizuku 在对性能的影响最小的情况下,极大地提高了使用 Shizuku 的应用的性能和可靠性。 此外,Shizuku 还为开发者提供了极大的便利。
> 有关 Shizuku 的信息,以及为什么要独立出一个应用,请查看 [shizuku.rikka.app](https://shizuku.rikka.app/zh-hans)。
================================================
FILE: appops/zh-hant/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: 立即下載
actionLink: /zh-hant/download.html
secondaryActionText: 瞭解更多
secondaryActionLink: /zh-hant/guide/
features:
- title: 訪問隱藏的權限機制
details: 藉助 App Ops 修改隱藏的 appops 設定來(部分)控制權限。
- title: 優秀的使用者經驗
details: 提供美觀、友好的使用者介面。App Ops 在很多不為人知的地方做出許多努力以降低使用難度。
- title: 無需 root 也可使用
details: 提供多種只需 adb 的工作模式。
- title: 跟隨最新的 Android 系統
details: 支援新版本 Android 的特性,即使是測試版系統也會在幾天內得到支援。
- title: 詳細的幫助
details: 提供詳細的幫助文件。
- title: 提供高階功能
details: 藉助模板、備份恢復等功能來方便操作。
footer: Copyright © 2019 RikkaApps
---
================================================
FILE: appops/zh-hant/changelog.md
================================================
# 變更日誌
## 9.0.6 (2023-08-03)
- 升級 Shizuku 到 13.5.0 以上可能可以解決自動化功能不工作的問題
- 修復在部分 realme 裝置上「無法啟動服務」的問題
- 修復在 Android 7.1 及之前版本崩潰
## 9.0.0 (2023-04-08)
- 為 Android 10 及以上版本新增「感測器」權限,可控制應用程式是否可以使用加速度計、重力感測器等無需權限即可使用的感測器
- 支援 Android 14(但是,根據經驗,應用程式很可能會因為之後的改動再次無法工作)
- 在 Android 11 以上針對目標 API 為 30 及以上的應用程式隱藏 `OP_TOAST_WINDOW`,因為其不再有效
- 在 Android 10 以上針對儲存權限新增說明,因為系統允許特定的應用程式寫入標準資料夾,即使其沒有儲存權限(特定的應用程式是指目標 API 是 30 或以上,或者目標 API 是 29 且適配了 Scoped Storage 的應用程式)
- 增加允許備份系統元件的選項
- 針對中日韓語言使用者,如果系統沒有提供 Medium(500)字重的字型,則會使用模擬實現
- 針對在三星裝置上出現的 `com.android.externalstorage`、`com.android.providers.downloads`、`com.samsung.android.providers.media` 無權限問題增加提示資訊
## 8.0.1 (2022-11-22)
- 未解鎖完整版時允許備份(恢復備份仍需要完整版)
- 修復切換使用者隨機失效
## 8.0.0 (2022-09-02)
- 針對 Android 12 及以上的實驗性功能:使用情況歷史
- 適配 Android 12 關於位置權限的變化
- Material Design 3
- 裝置管理員模式因為 Google Play 政策變化而被移除
## 5.5.6 (2022-06-10)
- 在 Android 13 Beta 3 上工作
- 修復使用法語時崩潰的問題
- 裝置管理員模式將要因為 Google Play 政策變化而被移除
## 5.5.2 (2022-03-10)
- 更換應用程式圖示,因為舊圖示「違反 Google Play 政策」
## 5.5.0 (2022-03-03)
- 在 Android 13 DP1 上工作(但是,根據經驗,DP1 是非常早期的版本,應用程序很可能會因為 DP2 的改動再次無法工作)
## 5.4.3 (2021-06-13)
- 修復「自動恢復」可能造成所有同組權限都被重設爲「忽略」的問題
## 5.4.2 (2021-06-01)
- 修復從 5.4.0 起備份不工作
- 修復低版本系統上的一些視覺問題
## 5.4.0 (2021-05-27)
- 修復在 Android 12 Beta 1 上剪貼簿監視器不工作的問題
- 修復在 Android 11 及以上版本,無法為安裝在工作資料的應用程式設定「忽略」的問題(此修復只在 Shizuku 模式下可能)
- 隱藏 `OP_QUERY_ALL_PACKAGES` 因為完全沒有用
- 隱藏 `OP_NO_ISOLATED_STORAGE` 因為它只用作除錯
## 5.3.3 (2021-05-04)
- 適應另一個 Android 12 的改變
- 阻止 💩 MIUI 的「強制深色模式」弄壞自己的深色主題<sup>**〔1〕**</sup>
<sub><b>〔1〕</b>MIUI 有自己的「強制深色模式」,但是似乎即使應用程式正確地提供了深色主題,它也會繼續起作用,從而把顏色改亂。</sub>
## 5.3.1 (2021-04-03)
- 修了一個可能導致崩潰的問題
- 適應一些 Android 12 的改變
## 5.3.0 (2021-01-28)
- 初步地加入正確處理 Shared user ID
## 5.2.0 (2021-01-16)
- 支援 Sui(https://github.com/RikkaApps/Sui)
## 5.1.3 (2020-11-29)
- 適應了「儲存空間隔離」v5 的變化
- 修瞭如果系統返回了「錯誤」的資料備份會壞掉的問題(但是已經壞了的備份檔案不可能修好)
## 5.1.2 (2020-10-07)
- 修復一個涉及建立備份的問題
- 修復一個涉及「剪貼簿監視器」的問題
- 修復「自動恢復」的記錄有時可能無法正確地被更新的問題
- 匯入來自使用者的翻譯
## 5.1.0 (2020-09-24)
- 「應用詳情」及「權限檢視」的的批量操作現在可以使用所有的選項(注意,選中多個項目時,顯示的選項為所有可用選項的交集)
- 「權限檢視」可以搜尋
## 5.0.6 (2020-09-06)
- 修復一個有關建立備份的問題
- 修復一個有關批量操作(包括使用模板、備份等)的問題
- 匯入來自使用者的翻譯
- 其他小改變
## 5.0.4 (2020-08-30)
- 修復了實際上未還原任何內容時「正在還原備份」也可能會顯示的問題
- 匯入來自使用者的翻譯
- 其他小改變
## 5.0.3 (2020-08-27)
- 修復 v5.0.2 (1236) 引入的問題
## 5.0.2 (2020-08-26)
- 為所有 Android 10 強制使用「自動恢復」選項,因為已確認 Android 10 也會進行重置(只是相較 Android 11 情況更少)
- 修復了在「託管裝置管理員模式」下錯誤地要求所有版本的 Island 請求了只有 Island 5.0+ 提供的功能的問題
- 修復了「自動恢復」的忽略選項實際上不起作用的問題
- 修復了模板中的 `RUN_IN_BACKGROUND` 在編輯後沒有正確顯示的問題
## 5.0.1 (2020-08-24)
- 修了上個版本將使用 DSM API v3 的管理員程式錯誤地標明為「缺少支援」的問題
- 修了上個版本的模板並沒有正確顯示所有選項
- 修了上個版本針對(以「隱藏」為原理的)凍結類應用的自動恢復備份功能壞掉的問題
- 在必要時重設 package mode(針對使用舊版 App Ops 或其他尚未正確適應系統變化的 appops 工具留下的「錯誤」設定)
- 匯入新增的使用者翻譯
## 5.0.0 (2020-08-22)
此更新解決了一個隱蔽但長期存在的問題。因為 Android 10 以下只在極少情況才出現,且升級到 Android 10 以後已有的設定不會被影響,這個問題在最近才浮出水面。一個典型的例子是,在 Android 10 中,一旦您從系統更改了位置權限,對舊版 App Ops 的更改將永遠無法生效(即使看起來成功地更改了)。
這背後包含很多工作,請閱讀[技術細節](./guide/technical/system_behaviors/)。
**您應該知道的內容:**
- 您在 App Ops 中看到或更改的內容現在反映最終狀態
- 舊版本中的「拒絕」被重新命名為「忽略」
- 不再支援舊備份,因為它們缺少必要的資訊(甚至可能包含錯誤的資訊)
- 對於「託管裝置管理員模式」,當前只有 Island v5.0+ 支援新的必要的 API
- 對於「託管裝置管理員模式」,備份的一部分來源於歷史使用者操作,這是因為管理員程式沒有足夠的權限來獲取準確的狀態(這是系統限制)
其他變化:
- 模板:不止「忽略」(「拒絕」),現在可以在模板中使用任何選項
- 備份:還原時更加靈活
- 使用情況監控器:嘗試減少「錯誤」報告(有時系統始終報告應用程式正在使用位置,即使該應用程式已經不再執行也是如此)
- 使用情況監控器 & 剪貼簿監視器:加入「排除系統應用程式」選項
## 4.2.3 (2020-07-18)
- Add Turkish translation
- "Usage monitor" fix
## 4.2.2 (2020-07-16)
- 解決了從 v4.0.0 起出現的小概率隨機停止執行問題
- 「使用情況監視器」改進
- 重新整理字串,任何人都可以參與翻譯
## 4.2.0 (2020-07-12)
- 增加「使用情況監視器」(需要 Android 9 以上和通過 root 啟動的 Shizuku)
當應用程式使用位置、相機或麥克風時收到提示
## 4.1.1 (2020-07-10)
- 剪貼簿監視:可設定「臨時訪問時限」
- 剪貼簿監視:修復一個有關「排除的程式」的 UI 問題
- 修復在 Android 10 以上,從 v4.0.0 起建立的備份可能損壞的問題
- 正確地回報來自託管裝置管理員模式的錯誤
- 暫時不使用 AAPT2 的資源優化功能,這可能可以解決部分使用者出現的隨機的設定介面崩潰問題
## 4.1.0 (2020-07-09)
- 剪貼簿監視:增加「視窗位置」和「排除的程式」選項
- 修復一旦主要程式死掉,「新程式行為」功能就會停止工作
- 修復權限檢視 UI 重新整理問題
## 4.0.1 (2020-07-05)
- 修復在某些情況下監視服務非正常地啟動
## 4.0.0 (2020-07-04)
用最新技術(部分)重寫。具有更多改進和新功能的全面重寫將在不久的將來出現。
- 新功能:剪貼簿監視(需要 Android 10 以上和通過 root 啟動的 Shizuku)<sup>**〔1〕**</sup>
- 在 Android 10 及 11 上工作
- 使用者介面翻新
- 修復一個有關恢復備份的問題
- 永遠使用內建的名稱<sup>**〔2〕**</sup>
- 對於免費版本,移除 Google Ads(轉而推薦我們的其他應用程式)
- 對於崩潰報告,使用 AppCenter 替代 Firebase Crashlytics(此外,崩潰報告可關閉)
- 目標 API 30
- 不再支援 system plugin 模式
- 不再支援 Android 6.0
- 不再支援古老的以 LineageOS 為基礎的 ROM 中的詢問模式<sup>**〔3〕**</sup>
<sub><b>〔1〕</b>從監視中排除應用程式的功能將在下個版本中加入</sub>
<br><sub><b>〔2〕</b>之前,權限的名稱被優先使用。但是隨著 Android 在每個版本間不斷改變權限名稱,權限名稱越來越不準確。</sub>
<br><sub><b>〔3〕</b>根據使用者報告,一些老舊的三星裝置表現得有這個功能,但是改為「詢問」將會導致系統無法啟動。</sub>
## 3.1.1 (2019-08-03)
- 修復無法編輯模板
## 3.1.0 (2019-08-02)
- 操作系統程式時提供更加明顯的警告
- 為套用模板對話方塊提供編輯與新增功能
- 修復使用託管裝置管理員模式時,如果先使用 Island 之後更換為其他也會被判定為正在使用 Island
## 3.0.3 (2019-07-29)
- 小 bug 修复
- 提供新的包含文档的网站:<https://appops.rikka.app/zh-hans>
## 3.0.2
- 修复托管设备管理员模式坏掉
- 修复错误的依赖
## 3.0.0
- 托管设备管理员模式:修复当使用 Island 时新应用安装可能不被出发
- (实验性)托管设备管理员模式:支持多用户(需要 Island 3.8+ 作为设备管理员,2019/7/24 在 Google Play alpha 通道提供)
- 模板:默认勾选「跳过检查」
- 模板:改进编辑 UI
- 如果一个 op 不被原生 Android 包含,显示提示
- 其他 bug 修复和 UI 改进
## 2.9.9
- 托管设备管理员模式:修复一些与 Island 支持有关的 bug
- 特权模式:修复总是需要旧式 Shizuku
- 显示所有工作模式(解释原因如果不支持)
## 2.9.8
- (实验性)托管设备管理员模式支持 Island 应用的「上帝模式」 (com.oasisfeng.island)
- 特权模式:修复「adb 权限不足」提示从未显示(主要只给 MIUI)
## 2.9.7
- Try to fix "Code 5"
## 2.9.5
- 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)
- Fix "Code 5 debug message: null" (by upgrading lib from Google :(
- Minor UI tweaks
## 2.9.4
- Target 29
- 修 2.9.2 带来的 bug
## 2.9.2
- 修复升级到 2.9.1 后模板丢失
- 通知语言现在应该完美跟随应用内语言设置
## 2.9.1
- 增加托管设备管理员模式(使用来自支持的设备管理员应用的 API)
- 修一些 bug
- 备份包含模板
## 2.8.2
- 修复 root 模式在 Android Q beta 3 上不工作
- 修复在低版本 Android 上少数功能可能不正常
- 修复「显示框架应用」选项在 root 模式下不工作
- 修复 root 模式下 overlay package 们没有被过滤
## 2.8.1
- 在 Android Q beta 3 上能用(但还不能看使用时间)
- 存储空间选项在 Q beta 3 上无效,这是系统 bug
- 暂时在 Q beta 3 上隐藏「存储空间沙盒」选项(默认关闭除非应用声明,如何强制开启方法尚不明确)
- 当未设定默认模板时自动设定第一个(用于拯救从不阅读提示的傻子)
## 2.8.0
- 支持 Android Q 添加的新 op
- UI 改进
## 2.7.0
- 在 Android 9 上再也不会出现「需要重启应用」
- 使用特权模式时不再会出现随机错误(需要升级到 Shizuku v3 并强行停止 App Ops)
## 2.6.4
- 更新其他语言的翻译
- 修复 bug
## 2.6.3
- 更新其他语言的翻译
- 修复 bug
## 2.6.2
- root 模式支持多用户(实验性)
- 为根据权限分组的列表加入「已禁用有限」选项
- 为 Android 9 用户优化控制「在后台运行」时的 UI
- 修复 bug
## 2.5.10
- 增加为 Android 9 准备的帮助
- 修复 bug
## 2.5.9
- 修复一个涉及多用户的 bug
## 2.5.8
- 修复 bug
## 2.5.7
- 简化详情界面 UI
- 修复当一些 op 的 opToSwitch 所对应的权限没有申请时就无法更改那些 op 的 bug
## 2.5.5
- 修复无 root 在 Android 9 上首次使用特权模式的流程
- 修复编辑中的模板如果进行旋转屏幕等操作会丢失已编辑内容的问题
- 编辑模板按下返回会询问是否保存
- 修复在模板名称按下回车会爆炸
- 默认隐藏未知的 op(对,又是你 MIUI)
## 2.5.3
- 修复一些关于新应用监控的问题
- 可能修复一些打开就爆炸
## 2.5.2
- 修复在 2.5.0 中系统插件模式无法使用
- 修复错误信息没有被正确展示
- 修复在 Android 7.x 上无法正常工作
- 修复部分 Google Play 用户会出现「您已拥有此物品」的问题
- 为了让监控新应用安装功能更加可靠,现在它需要运行一个前台服务(仅 Android 8.0 以上),
但你可以禁用或将其设定为最低重要程度来避免被打扰
## 2.5.0
- 为 Android 9+ 移除系统插件(因为只有在插件拥有系统签名时才能工作)
- 简化系统插件安装,只提供 zip 下载
- 支持 Android 9 添加的 appops 特性(如 MODE_FOREGROUND 和 OP_RUN_ANY_IN_BACKGROUND)
- 新的 UI
- 多组模板
- 解决当长时间后返回, app 无法使用的问题
## 2.4.1
- 更新翻译
- 尝试修复部分付费用户会被当作未付费用户的问题
## 2.4.0
- 提升 root 模式速度
## 2.3.13
- 尝试修复 root 模式在部分设备无法工作
- 改变 Android 8+ 上的图标
## 2.3.12
- 尝试修复在恢复备份时可能崩溃
## 2.3.11
- 为所有列表添加全选(长按 -> 菜单里的三个点点 -> 全选)
- 系统插件模式现在为 Magisk 用户提供 template v1500 的模块
## 2.3.10
- 修复当恢复大量备份时崩溃
- 修复提示对话框内容不可以滚动的问题
## 2.3.9
- 修了在 Android P DP1 上崩溃(你可能会看到 "Detect problems with API compatibility" 的提示,但是对 App Ops 来说不使用隐藏 API 是不可能的)
## 2.3.8
- 增加「显示全部模式」选项(不懂是什么就别打开)
## 2.3.7
- _始终显示权限(操作)_ 将会排除一些绝对不可能的情况
- 增加被安装到外部存储的错误提示(都 8012 了怎么还有这种人)
- 更新葡萄牙语(巴西)翻译
- 移除一些未使用资源
- 修复创建备份坏掉
## 2.3.6
- 修了总是提示 Google play 不可用
- 增加一个显示全部支持的权限(操作)的列表
- 在应用列表中标记系统应用
- 增加 _始终显示的权限(操作)_ 列表,每个应用都会被当作可能使用选中的权限
- 调整设置 UI
## 2.3.5
- 修复备份预览坏掉
- 增加本地网络(特权模式需要使用)受限时的提示
- 处理一些未捕获的错误
## 2.3.4
- 修复 root 模式下重置无效的问题(真·上古 bug)
- 修复从应用列表重置或应用模板不会刷新 UI 的问题
## 2.3.3
- 修了两个上古 bug
## 2.3.2
- 修了 2.3.0 留下的 bug
- 异步读取其他信息(比如已修改的项数),因此现在读取应用列表速度会非常快
## 2.3.0
- 为应用列表增加已修改的项数
- 极大加速 root 模式下获取 appops 配置的速度
- Oreo 风格的应用详情视图
- 支持 Android 8.1 的亮色导航栏
- 修改一些令人疑惑的 UI
- (免费用户) 因为 Google 将在 2018 年 3 月后移除快捷原生广告,所以换回旧的横幅广告
- 修复一些和多用户有关的问题
- (付费用户) 修复在应用安装后,即使备份存在且打开了恢复备份,只要模板存在就被套用的问题
- 因为一些原因,移除对旧的 Shizuku (特权模式)的支持
## 2.2.6
- 修复 Shizuku Manager 比 App Ops 安装晚会无法使用的问题
## 2.2.5
- 为新应用监控添加开机启动
- 添加 Portuguese (Brazil) 语言
## 2.2.4
- 增加针对 adb 有读取 appops 配置但没有写入权限时的提示(比如 MIUI MIUI 和 MIUI)
- 使用新的 build tool 来避免一个只在部分低版本第三方 ROM 上出现的可怕的问题 ([看这里](https://issuetracker.google.com/issues/64434571))
## 2.2.3
- 修复_特权模式_使用旧版 _Shizuku Manager_ 可能会崩溃的问题
- 从通知套用模板时不再检查是否有 `RUN_IN_BACKGROUND`
- 修复切换工作模式时设置崩溃
## 2.2.2
- 修复选择_特权模式_时没有安装 _Shizuku Manager_ 会崩溃
## 2.2.1
- 增加指定界面语言的功能
- 更新翻译
- 通过反射 `PackageInfo#overlayTarget` 的方式过滤 overlay apps
- 修了新应用通知上的按钮在部分设备上可能不能用的问题
- 套用模板时不再检查是否有 `RUN_IN_BACKGROUND`
## 2.2.0
- 修复套用模板或恢复备份后通知不能消除的问题
- 重新规划主菜单项目
- 将「显示框架应用」移至主菜单
- 增加「根据更新时间排序」,「根据安装时间排序」
- 实验室增加 "Show target 0 apps" (为了过滤掉 substratum overlay)
- 重构设置向导,同时增加更多说明
- 调整设置 UI
- 修复通知不能显示自适应图标 (8.0+)
## 2.1.12 (beta)
- 在获取应用列表是请求更少数据
> 解决部分设备上只能获得部分应用(甚至出现 "Package Manager has died")的问题。
> 会加快列表刷新速度。
> 但没有那些数据,we have to remove "show apps without icon" option because we can't know
if the app have a entrance, and "run in background" (Android 7.0+) will always shown because we can't
speculated if the app have background behavior.
- (特权模式)让 Shizuku manager 展示服务没有运行
- 新的版本号明明规则
- 适配 Font Provider API v8
## 2.1.11
- Fix system plugin broadcast does not work
- Fix notification didn't show when plugin stopped
- Improve Settings UI for RTL language
- 引入 Shizuku v2 (特权模式),加入 Shizuku Manager 的测试来尝试
- Font Provider 默认开启
## 2.1.10
- 当系统插件权限不足时给用户更友好的提示
- 再次修复使用系统插件时有时需要手动刷新
- 更新 Font Provider 依赖到 1.3.2,应该没问题了
- 增加更多帮助
- 修了一些对话框的按钮颜色
## 2.1.9
- Fix NPE in WorkService
- Move system plugin download to GitHub release
- Fix crash when open help in runtime permission tip dialog
- Notify list refresh when system plugin connected
- Update translation
- Add translator's name to about
## 2.1.2 - 2.1.8
- 修复无法创建备份文件
- 实验室(包含未确定或实验性功能)功能入口现在总是显示
- Provide fastScroll drawable from AOSP to avoid crash on some devices
- Update help
- Fix test link in pro version
- 100% fix theme and night mode, it should work perfectly now
- Update adaptive icon for Android O
- Add tip of Runtime Permissions when entering app target 23+
- 改进的主题
- 提供一个新的选项来使用 "Noto Sans CJK Medium" 替换 "sans-serif-medium" 字体(需要配合 Font Provider 应用使用)
- Add tip for users can't use system plugin on Android O
## 2.1.1
- 增强的备份功能 (PRO)
- 当用户改变权限设置后,设置会被自动保存至数据库。当应用在卸载后再次安装或是被使用设备管理器的冻结类应用(如[冰箱](https://play.google.com/store/apps/details?id=com.catchingnow.icebox)的免 root模式)禁用后重新启用后可以选择恢复。
- 增加详细的更新日志
- 新的更详细的帮助
================================================
FILE: appops/zh-hant/download.md
================================================
# 下載
[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)
[Coolapk](https://www.coolapk.com/apk/rikka.appops)
[GitHub](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/tag/files)
================================================
FILE: appops/zh-hant/guide/README.md
================================================
# 瞭解 App Ops
簡而言之,**App Ops** 是一個修改 **Android 系統中的 "appops" 設定** 的程式。
## 什麼是 Android 系統中的 "appops"
在 Android 系統中存在一個叫做 "appops" 的系統服務,該服務定義了一系列的「程式操作」(application operation, op)。其中部分「程式操作」與「權限」對應(如 `OP_CAMERA` 與「相機權限」),其餘則對應單獨的功能(如 `OP_READ_CLIPBOARD` 與讀取剪貼簿,但並不存在「讀取剪貼簿權限」)。
原生 Android 系統使用 appops 來追蹤權限使用,appops 也部分被用於權限控制。每個程式都有自己的 "appops" 設定,當程式需要執行某些操作時,系統在檢查權限的同時也會檢查 "appops" 設定。如果沒有授予權限,程式在執行操作時將會收到錯誤。但不同的是,如果 "appops" 設為忽略<sup>**〔1〕**</sup>,程式不會收到錯誤只會收到空白資料<sup>**〔2〕**</sup>。
但是原生 Android 系統並沒有提供修改 "appops" 設定的使用者介面。
<sub>**〔1〕** App Ops 程式中實際將「忽略」顯示為「拒絕」</sub>
<br><sub>**〔2〕** 實際行為取決於系統,程式也可檢查 "appops" 是否被拒絕</sub>
## 什麼是 App Ops 程式
App Ops 程式的核心功能是修改系統 "appops" 設定,可以在某種意義上實現權限管理。App Ops 程式還做出很多努力簡化許多技術細節,讓使用更加簡單。
## 用語宣告
### 「權限」
App Ops 實際修改的是「程式操作」而非「權限」,但為了降低難度將其稱為「權限」。App Ops 程式**不可以直接操作「權限」**,請不要誤解。
::: tip
幫助中的其他地方仍稱其為「權限」。
:::
## App Ops 的限制
### 可以修改的權限取決於系統
App Ops 所能修改的權限**只取決於你的系統**,所以别再問「為什麼沒有 XXX 權限」了。
通常,系統版本越高,能修改的內容越多(廠商或自定義 ROM 可能會新增自己的權限)。所有你的系統支援的權限可以在 設定 - 行為 - 全部權限 中看到。
### 程式仍可以獲知沒有權限
程式可以檢查返回資料是否為空白,或是直接檢查 "appops" 是否被允許。只是很少有程式這麼做。
================================================
FILE: appops/zh-hant/guide/faq/how_to_reset.md
================================================
# 如何重置全部設定?
1. 切換到應用列表模式
2. 長按或點選左側應用圖示進入多選模式
3. 右上方三點選單 - 全選
4. 選擇「重置」
================================================
FILE: appops/zh-hant/guide/faq/purchase.md
================================================
# 購買或恢復問題
## Google Play 恢復問題
大部分情況下,按照點擊購買後出現的提示文字處理即可,如果仍不能解決問題,請發送郵件給我們。
================================================
FILE: appops/zh-hant/guide/technical/run_in_background.md
================================================
# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`(在後臺執行)
在 App Ops 應用中看到的「在後臺執行」實際是指 `RUN_IN_BACKGROUND`(Android 7 起增加)和 `RUN_ANY_IN_BACKGROUND`(Android 9 起增加)這兩個 op。在不同的系統版本上,改變這些 op 會有不同的行為。
這篇文章將會說明在 Android 9 上修改 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 對應用行為的影響。
## App Ops 應用所做的特殊處理
為了應對 Android 9 新增加的 `RUN_ANY_IN_BACKGROUND`,App Ops v2.6.0 以前採取這樣的策略:直接將 `RUN_IN_BACKGROUND` 和 `RUN_ANY_IN_BACKGROUND` 視為同一個,即只會看到一個「在後臺執行」選項,修改時會同時修改這兩個。但部分特殊情況下,同時設定兩個會造成限制過於嚴格的問題,因此從 v2.6.0 起可以自行選擇限制哪一個。
## `RUN_IN_BACKGROUND`
> 文章尚未完成,更多資訊將在以後補充
所有 target API 在 26 及以上的應用會受到此限制。
參考以下文章:
https://developer.android.com/about/versions/oreo/background
## `RUN_ANY_IN_BACKGROUND`
> 文章尚未完成,更多資訊將在以後補充
參考以下文章:
https://developer.android.com/about/versions/pie/power#battery-saver
https://developer.android.com/topic/performance/power/power-details
部分涉及的 commit:
https://github.com/aosp-mirror/platform_frameworks_base/commit/3ac1daac4044c70ad4ee673214074306de499a18
https://github.com/aosp-mirror/platform_frameworks_base/commit/db6bf66ee3b82edf25874d5dea4e02b0a146fb16
================================================
FILE: appops/zh-hant/guide/technical/system_behaviors.md
================================================
# 不同 Android 版本下的不同
每個 op 都有兩種 mode,分別為 `package mode` 和 `uid mode`。`uid mode` **有更高優先順序**,即只有當 `uid mode` 為預設值時才會使用 `package mode`。
以下表格展示了從系統修改權限設定時,`uid mode` 會被如何設定。
::: details 表格
<p>
星號(*)表示相對之前的系統放生變化。
#### Android 6 - Android 9
| 系統設定頁面 | uid mode |
|--------------|-----------------------------------------|
| 允許 | allow |
| 拒絕 | ignore(只對 target 23 以下的應用程式設定) |
| (尚未設定) | (allow) |
#### Android 10
| 系統設定頁面 | uid mode |
|--------------------|------------|
| 僅在使用期間允許 * | foreground |
| 允許 | allow |
| 拒絕 * | ignore |
| (尚未設定) | (allow) |
#### Android 11
| 系統設定頁面 | uid mode |
|--------------------|------------|
| 每次都詢問 * | ignore |
| 僅在使用期間允許 * | foreground |
| 允許 | allow |
| 拒絕 | ignore |
| (尚未設定)* | ignore |
#### Android 11 中的其他行為
* 設定 `package mode` 無效
* 設定 `uid mode` 時,若設定值不符合執行時權限狀態則無效
* 在特定的情況下(比如安裝應用程式後),系統將重設**全部應用程式**的 appops 設定到與執行時權限符合的狀態
:::
### 舊版本 App Ops 沒做對
舊版本的 App Ops(v5.0.0 以前)只會讀取和修改 `package mode`,這顯然是不對的。
在 Android 9 及之前,對 target 23 以下的應用程式在 App Ops 中設定「允許」是無效的;在 Android 10,一旦使用者在系統中設定「拒絕」或「僅在使用時允許」,則在 App Ops 中的設定永遠無法生效(因為此時系統設定的 `uid mode` 被優先使用)。
由於從低版本升級時系統的權限設定是被保留的,這個巨大的問題在 Android 10 釋出的一年後才慢慢地暴露出來。
### 新版本(v5.0.0)App Ops 所做出的變化
除了完全跟隨系統行為以外別無選擇。
另外,因為 Android 11 會重置 appops 設定(所有「執行時權限允許,ops 忽略」會被重設為「執行時權限拒絕」),所以除了在系統之後再次重設以外別無選擇。
### 新版本(v5.0.0)App Ops 需要更多能力
想要正確跟隨系統行為,App Ops 必須具備取得和設定 `runtime permission`,`permission flags`,`appops` 的能力。但是,並不是所有工作模式都能做到。
| | Shizuku 模式 | 託管裝置管理員模式 | root 模式(已被移除) |
|--------------------|--------------|------------------------------|-----------------------|
| appops | ✔️ | ✔️ | ✔️ |
| runtime permission | ✔️ | 僅可設定<sup>**〔1〕**</sup> | ❌ |
| permission flags | ✔️ | ❌ | ❌ |
<sub><b>〔1〕</b>需要 Island v5.0+ 或其他具有 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) v3 支援的管理員程式</sub>
#### 「託管裝置管理員模式」的缺陷
* 「無法確認」
* 無法備份全部設定
* 在 Android 11,無法設定新增的「每次都詢問」(需要「設定 permission flags」)
::: details 技術資訊
被設為 `profile owner` 或 `device owner` 的管理員程式享有一些特權,但是隻有它們自身可以使用。因此,不同的管理員程式提供了不同的 API,使其他應用程式得以「借用」其特權。
* [Delegated Scopes Manager API](https://github.com/heruoxin/Delegated-Scopes-Manager)
* [Delegation API](https://island.oasisfeng.com/api)
只有提供 Delegation API 的 Island v5.0+ 支援「設定 runtime permission」。
對於「無法確認」,舉個例子,在 Android 10 中:
| | appops | runtime permission | permission flags |
|--------------|------------|--------------------|------------------|
| 忽略 | ignore | true | |
| 拒絕 | (任何值) | false | 任意 "FIXED" |
| (尚未設定) | (任何值) | false | 無 "FIXED" |
只看 appops 設定顯然不夠。
:::
#### 為什麼必須移除「root 模式」
純 root(執行指令)的能力十分有限,沒有可以修改 permission flags 的指令。想要正確修改 runtime permission 必須保證 permission flags 也被正確地修改(裝置管理員所使用的更高層級的 Java API 不需要考慮這個問題)。
因此,root 模式已被移除。
::: details 技術資訊
很多人會認為 root 無所不能,但實際上 root 只提供了一個 `uid 0` 的 shell。想要進入 Android 世界(直接使用 Java API),通過 `app_process` 執行 dex 幾乎是唯一選擇。
「root 模式」的替代——「Shizuku 模式」使用 Shizuku([GitHub](https://github.com/RikkaApps/Shizuku))做這一部分的工作。如果不使用 Shizuku,則仍然需要執行類似 Shizuku 的東西,這樣做是沒有意義的,並且也將帶來無意義的資源使用。
:::
================================================
FILE: appops/zh-hant/guide/working_mode/dpm.md
================================================
# 託管裝置管理員模式
::: warning 警告
從 6.0.0 起,此工作模式不再支援。若要繼續使用此工作模式,請[下載 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-tracker/releases/download/files/appops-v5.5.6.r1453.f44c5855.apk)。
:::
## 需求及特性
* 需要 Android 9+
* 需要安裝其他應用程式,並使用 adb 將其設為 Device owner
* 是否支援多使用者取決於 Device owner 應用程式
## 背景
託管裝置管理員模式是 App Ops 從 v2.9.0 開始加入的新的工作模式。從 Android 9 開始,裝置管理員開始可以修改 appops 設定,但系統限制一臺裝置上僅能設定一個程式為裝置管理員。因此 App Ops 使用由其他裝置管理員程式提供的 API。
從 v2.9.0 起支援使用 [Delegated Scopes Manager](https://github.com/heruoxin/Delegated-Scopes-Manager) 的裝置管理員程式。
從 v2.9.8 起支援另一種[由 Island 提供的 API](https://island.oasisfeng.com/api)。
## 免責聲明
你需要安裝的裝置管理員程式都不是由我們開發。
::: warning
裝置管理員在 Samsung 裝置及很多來自中國大陸地區廠商的裝置上或多或少存在一些問題,請務必仔細閱讀來自裝置管理員程式提供的幫助,如果你無法接受可能的問題,請不要使用。
:::
::: danger
Samsung 裝置在使用裝置管理員後可能造成無法挽回的結果(參閱 [來自 冰箱 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)),請務必謹慎。
:::
## 如何使用
設定過程需要連線電腦使用 adb,但只需要進行一次設定。
### 1. 安裝及設定裝置管理員程式
#### 冰箱 IceBox
1. 下載 [Google Play](https://play.google.com/store/apps/details?id=com.catchingnow.icebox) 或 [Coolapk](https://www.coolapk.com/apk/com.catchingnow.icebox)
2. 參閱 [幫助](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) 為其設定裝置管理員模式
#### 小黑屋
1. 下載 [Google Play](https://play.google.com/store/apps/details?id=web1n.stopapp) 或 [Coolapk](https://www.coolapk.com/apk/web1n.stopapp)
2. 參閱 [幫助](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)(僅提供簡體中文) 為其設定裝置管理員模式
#### Island
1. 下載 [Google Play](https://play.google.com/store/apps/details?id=com.oasisfeng.island) 或 [Coolapk](https://www.coolapk.com/apk/com.oasisfeng.island)
2. 參閱 [幫助](https://island.oasisfeng.com/setup.html) 為其設定裝置管理員模式(Island 稱其為「上帝模式」)
### 2. 授予權限
在 App Ops「設定」-「工作模式」中選擇「託管裝置管理員模式」後返回程式列表應該會彈出來自裝置管理員程式的授權對話方塊,請在勾選「修改 app ops」後確認。
接著,你還需要使用使用 adb 授予 App Ops 「獲取 app ops」 權限。使用以下的指令:
```
adb shell pm grant --user 0 rikka.appops android.permission.GET_APP_OPS_STATS
```
注意,如果你將 App Ops 程式安裝到其他使用者,需要將其中 `--user 0` 的 `0` 替換為其他使用者的 id(使用 `adb shell pm list users` 獲得的 `UserInfo{0:Owner:13} running` 的結果中的 `0` 即為使用者 id)。
### 3. 授予多使用者許可權
對於多使用者支援,你還需要執行下面的指令來讓 App Ops 可以部分訪問其他使用者:
```
adb shell pm grant --user 0 rikka.appops android.permission.INTERACT_ACROSS_USERS
```
::: tip
目前只有 Island 3.8+ 支援多使用者
:::
### 4. 遇到問題?
* 使用 Island 時出現 `Cannot request permission without a restrictions provider registered`
清除 Island 的快取(應用資訊 -> 儲存 -> 清除快取),後重新啟動 Island。
================================================
FILE: appops/zh-hant/guide/working_mode/shizuku.md
================================================
# Shizuku 模式
## 需求及特性
* 需要安裝 Shizuku 應用程式並通過 adb 或 root 啟動 Shizuku 服務
* 支援多使用者
::: tip
如果使用 adb,每次開機都需要使用 adb 進行啟動 Shizuku 的步驟(**但 appops 設定總是生效**)
:::
## 背景
Shizuku 是一個免費且[開源](https://github.com/RikkaApps/Shizuku)的類似於框架的應用程式。它旨在服務多個需要 root 或 adb 的應用程式。Shizuku 在對效能的影響最小的情況下,極大地提高了使用 Shizuku 的應用程式的效能和可靠性。 此外,Shizuku 還為開發人員提供了極大的便利。
> 有關 Shizuku 的資訊,以及為什麼要獨立出一個應用程式,請檢視 [shizuku.rikka.app](https://shizuku.rikka.app/zh-hant)。
================================================
FILE: assets/SourceCodePro-BDC.css
================================================
@font-face {
font-family: 'Source Code Pro BDC';
src: local('Source Code Pro'), local('SourceCodePro-Regular.ttf'), url('../fonts/SourceCodePro-BDC-Regular.woff2') format('woff2');
font-weight: 400;
font-display: swap;
font-style: normal;
unicode-range: U+2500-259F;
}
================================================
FILE: package.json
================================================
{
"dependencies": {
"moment": "^2.29.1",
"vuepress": "^1.8.2",
"vuepress-plugin-clean-urls": "^1.1.2",
"vuepress-plugin-sitemap": "^2.3.1"
},
"scripts": {
"appops:dev": "vuepress dev appops",
"appops:build": "vuepress build appops",
"shizuku:dev": "vuepress dev shizuku",
"shizuku:build": "vuepress build shizuku",
"sr:dev": "vuepress dev storage_redirect",
"sr:build": "vuepress build storage_redirect",
"www:dev": "vuepress dev www",
"www:build": "vuepress build www"
}
}
================================================
FILE: shizuku/.gitignore
================================================
/.vuepress/dist
================================================
FILE: shizuku/.vuepress/config.js
================================================
const moment = require('moment')
const langMap = {
"zh-Hans": "zh-cn",
"zh-Hant": "zh-tw"
}
var timestampCache = {}
module.exports = {
base: '/',
title: 'Shizuku',
head: [
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],
['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],
['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],
['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],
['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],
['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],
['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],
['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],
['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],
['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],
['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],
['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],
['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]
],
locales: {
'/': {
lang: 'en',
description: 'Let your app use system APIs directly'
},
'/zh-hans/': {
lang: 'zh-Hans',
description: '让你的应用直接使用系统 API'
},
'/zh-hant/': {
lang: 'zh-Hant',
description: '讓你的應用程式直接使用系統 API'
}
},
themeConfig: {
locales: {
'/': {
selectText: 'Languages',
label: 'English',
serviceWorker: {
updatePopup: {
message: "New content is available.",
buttonText: "Refresh"
}
},
sidebar: {
},
nav: getNavbar('/', 'Introduction', 'User manual', 'Download', 'Developer guide'),
lastUpdated: 'Last Updated'
}
,
'/zh-hans/': {
selectText: '语言',
label: '简体中文',
editLinkText: '在 GitHub 上编辑此页',
serviceWorker: {
updatePopup: {
message: "发现新内容可用.",
buttonText: "刷新"
}
},
sidebar: {
},
nav: getNavbar('/zh-hans/', '简介', '用户手册', '下载', '开发者指南'),
lastUpdated: '最后更新'
},
'/zh-hant/': {
selectText: '語言',
label: '繁體中文',
editLinkText: '在 GitHub 上編輯此頁',
serviceWorker: {
updatePopup: {
message: "發現新內容可用.",
buttonText: "重新整理"
}
},
sidebar: {
},
nav: getNavbar('/zh-hant/', '簡介', '使用者手冊', '下載', '開發者指南'),
lastUpdated: '最後更新'
}
},
displayAllHeaders: true,
sidebarDepth: 2,
serviceWorker: {
updatePopup: true
},
repo: 'https://github.com/RikkaApps/Shizuku',
docsRepo: 'https://github.com/RikkaApps/websites',
docsDir: 'shizuku',
editLinks: true
},
plugins: [
[
'sitemap',
{
hostname: 'https://shizuku.rikka.app',
exclude: ['/404.html'],
dateFormatter: (time) => {
timestampCache[time]
}
}
],
[
'clean-urls',
{
normalSuffix: '/',
indexSuffix: '/',
notFoundPath: '/404.html'
}
],
[
'@vuepress/last-updated',
{
transformer: (timestamp, lang) => {
var original = timestamp
moment.locale(langMap[lang])
var localized = moment(original).format('lll')
moment.locale('en')
var iso = moment(original).toISOString()
timestampCache[localized] = iso
return localized
}
}
]
]
}
function getNavbar(prefix, introduction, guide, download, dev) {
return [
{ text: introduction, link: `${prefix}introduction` },
{ text: guide, link: `${prefix}guide/setup.html` },
{ text: dev, link: `https://github.com/RikkaApps/Shizuku/blob/master/README.md` },
{ text: download, link: `${prefix}download.html` },
]
}
================================================
FILE: shizuku/.vuepress/public/icon/browserconfig.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<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>
================================================
FILE: shizuku/.vuepress/public/icon/manifest.json
================================================
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
================================================
FILE: shizuku/.vuepress/theme/index.js
================================================
module.exports = {
extend: '@vuepress/theme-default'
}
================================================
FILE: shizuku/.vuepress/theme/layouts/Layout.vue
================================================
<template>
<ParentLayout/>
</template>
<script>
import ParentLayout from '@parent-theme/layouts/Layout.vue'
export default {
components: {
ParentLayout
}
}
</script>
================================================
FILE: shizuku/.vuepress/theme/styles/index.styl
================================================
code
overflow: auto
word-wrap:break-word
body
font-family Roboto, sans-serif
body:lang(zh-hans)
font-family Roboto, 'Noto Sans SC', sans-serif
body:lang(zh-hant)
font-family Roboto, 'Noto Sans TC', sans-serif
================================================
FILE: shizuku/.vuepress/theme/styles/palette.styl
================================================
$accentColor = #3949ab
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34
================================================
FILE: shizuku/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: Learn more
actionLink: /introduction.html
features:
- title: Use system APIs elegantly
details: Forget about root shell, you can use APIs with higher privileges "directly". Also, Shizuku is significantly faster than shell.
- title: Supports adb usage
details: If your "root required app" only needs adb permission, you can easily expand the audience by using Shizuku.
- title: Save your time
details: Shizuku has detailed documentation to guide users. Only you need to do is to let the users install Shizuku.
footer: Copyright © 2019 RikkaApps
---
### As Easy as you are a system app
```java
private static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(
new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));
public static void grantRuntimePermission(String packageName, String permissionName, int userId) {
try {
PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);
} catch (RemoteException tr) {
throw new RuntimeException(tr.getMessage(), tr);
}
}
```
::: tip
There a few more steps to do, like checking permission or if Shizuku is running.
:::
================================================
FILE: shizuku/download.md
================================================
# Download
[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)
[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)
[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)
================================================
FILE: shizuku/guide/setup.md
================================================
# User manual
[[toc]]
## Start Shizuku
Shizuku supports startup in the following three ways.
::: tip If you are using GrapheneOS
System settings - "Security" - "Secure app spawning" may need to be disabled.
[Source](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)
:::
### Start with root
For rooted devices, just start directly.
### Start via wireless debugging
Starting 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.
#### Enable Wireless debugging
1. Search the web for how to enable "Developer options" for your device model
2. Enable "Developer options" and "USB Debugging"<br><br><img :src="$withBase('/images/enable_dev_options.png')" style="max-width:320px;width:100%">
3. Enter "Wireless debugging"<br><br><img :src="$withBase('/images/enter_wireless_debugging.png')" style="max-width:320px;width:100%">
4. Enable "Wireless debugging"<br><br><img :src="$withBase('/images/enable_wireless_debugging.png')" style="max-width:320px;width:100%">
#### Pairing (only needs once)
1. Start pairing in Shizuku<br><img :src="$withBase('/images/start_paring_from_shizuku.png')" style="max-width:320px;width:100%">
2. [Enable Wireless debugging](#enable-wireless-debugging)
3. Tap "Pair device with pairing code" in "Wireless debugging"<br><img :src="$withBase('/images/start_pairing.png')" style="max-width:320px;width:100%">
4. Enter pairing code in Shizuku's notificaiton<br><img :src="$withBase('/images/enter_pairing_code.png')" style="max-width:320px;width:100%">
#### Start Shizuku
<img :src="$withBase('/images/start_shizuku.png')" style="max-width:320px;width:100%">
If it does not start, try disabling and enabling wireless debugging.
### Start by connecting to a computer
This 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.
#### What is `adb`?
Android 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.
See [Android Developer](https://developer.android.com/studio/command-line/adb) for more information.
#### Install `adb`
1. Download "SDK Platform Tools" provided by Google and extract it to any folder
* [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)
* [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)
* [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)
2. Open the folder, right click to select
* Windows 10: Open PowerShell windows here (**hold down Shift to show this option**)
* Windows 7: Open command window here (**hold down Shift to show this option**)
* Mac or Linux: Open Terminal
3. Enter `adb`, if success, you can see a long list of content instead of the prompt not finding adb.
::: tip
1. 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)
2. If you use PowerShell or Linux/Mac, all `adb` should be replaced with `./adb`
:::
#### Setting `adb`
To use `adb` you first need to turn on USB debugging on your device, usually by following these steps:
1. Open system Settings and go to About.
2. Click "Build number" quickly for several times, you can see a message similar to "You are a developer".
3. At this point, you should able to find "Developer Options" in Settings, enable "USB Debugging".
4. Connect the device to the computer and type `adb devices` in the terminal.
5. At this time, the dialog "Allow debugging" will appear on the device, check "Always allow" and confirm.
6. Enter `adb devices` again in the terminal. If there is no problem, you will see something like the following.
```
List of devices attached
XXX device
```
::: tip
The steps for enabling Developer Options on different devices may vary, please search for yourself.
:::
#### Start Shizuku
Copy the command and paste into the terminal. If there is no problem, you will see that Shizuku has started successfully in Shizuku app.
::: details Command for Shizuku v11.2.0+
```
adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh
```
:::
## FAQ
Many manufacturers have made modifications to the Android system that prevent Shizuku from working properly.
### Start via wireless debugging: keeps showing "Searching for pairing service"
Please allow Shizuku to run in the background.
Searching 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.
### Start via wireless debugging: immediately fail after tapping "Enter pairing code"
#### MIUI (Xiaomi, POCO)
Switch notification style to "Android" from "Notification" - "Notification shade" in system settings.
### Start via wireless debugging/Start by connecting to a computer: the permission of adb is limited
#### MIUI (Xiaomi, POCO)
Enable "USB debugging (Security options)" in "Developer options". **Note that this is a separate option from "USB debugging".**
#### ColorOS (OPPO & OnePlus)
Disable "Permission monitoring" in "Developer options".
#### Flyme (Meizu)
Disable "Flyme payment protection" in "Developer options".
### Start via wireless debugging/Start by connecting to a computer: Shizuku randomly stops
#### All devices
- Make sure Shizuku can run in the background.
- Do not disable "USB debugging" and "Developer options".
- Change the USB usage mode to "Charge only" in the "Developer options".
On Android 8, the option is "Select USB configuration" - "Charge only".
On Android 9+, the option is "Default USB configuration" - "No data transfer".
- (Android 11+) Enable "Disable adb authorization timeout" option
#### EMUI (Huawei)
Enable "Allow ADB debugging options in 'Charge only' mode" in "Developer options".
#### MIUI (Xiaomi, POCO)
Do not use the scan feature in MIUI's "Security" app, since it will disable "Developer options".
#### Sony
Don't click the dialog shows after connecting the USB, because it will change USB usage mode.
### Start via root: cannot start on boot
Please allow Shizuku to run in the background.
================================================
FILE: shizuku/introduction.md
================================================
# Introduction
Shizuku can help normal apps uses system APIs directly with adb/root privileges with a Java process started with app_process.
The name Shizuku comes from [a character](https://danbooru.donmai.us/posts/3553474).
## Why was Shizuku born?
The birth of Shizuku has two main purposes.
1. Provide a convenient way to use system APIs
2. Convenient for the development of some apps that only requires adb permissions
## Shizuku vs. "Old school" method
### "Old school" method
For example, to enable/disable components, some apps that require root privileges execute `pm disable` directly in `su`.
1. Execute `su`
2. Execute `pm disable`
3. (pre-Pie) Start the Java process with app_process ([see here](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm))
4. (Pie+) Execute the native program `cmd` ([see here](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/))
5. Process the parameters, interact with the system server through the binder, and process the result to output the text result.
Each 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)
The disadvantages of this type of method are:
1. **Extremely slow**
2. Need to process the text to get the result
3. Features are subject to available commands
4. Even if adb has sufficient permissions, the app requires root privileges to run
### Shizuku method
The Shizuku app will direct the user to run a process (Shizuku service process) using root or adb.
1. When the app process starts, the Shizuku service process sends the binder to the app process.
2. The app interacts with the Shizuku service through the binder, and the Shizuku service process interacts with the system server through the binder.
The advantages of Shizuku are:
1. Minimal extra time and performance consumption
2. It is almost identical to the direct invocation API experience (app developers only need to add a small amount of code)
================================================
FILE: shizuku/zh-hans/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: 了解更多
actionLink: /zh-hans/introduction.html
features:
- title: 优雅地使用系统 API
details: 忘掉 root shell 吧,你可以「直接使用」需要高权限的 API。此外,Shizuku 比 shell 要快得多。
- title: 支持 adb 使用
details: 如果你的「需要 root 的应用」只需要 adb 权限,则可以使用 Shizuku 轻松地扩大用户群体。
- title: 节省时间
details: Shizuku 有详细的文档引导用户,你只需要让用户安装 Shizuku。
footer: Copyright © 2019 RikkaApps
---
### 就像是系统应用一样简单
```java
private static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(
new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));
public static void grantRuntimePermission(String packageName, String permissionName, int userId) {
try {
PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);
} catch (RemoteException tr) {
throw new RuntimeException(tr.getMessage(), tr);
}
}
```
::: tip
还有一些步骤要做,比如检查权限或 Shizuku 是否正在运行。
:::
================================================
FILE: shizuku/zh-hans/download.md
================================================
# 下载
[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)
[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)
[Coolapk](https://www.coolapk.com/apk/moe.shizuku.privileged.api)
[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)
================================================
FILE: shizuku/zh-hans/guide/setup.md
================================================
# 用户手册
[[toc]]
## 启动 Shizuku
Shizuku 支持通过以下三种方式启动。
::: tip 如果您正在使用 GrapheneOS
您可能需要关闭 系统设置 - “安全” - “Secure app spawning”。
[来源](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)
:::
### 通过 root 启动
如果您的设备已经 root,直接启动即可。
### 通过无线调试启动
通过无线调试启动适用于 Android 11 或以上版本。这种启动方式无需连接电脑。由于系统限制,每次重新启动后都需要再次进行启动步骤。
#### 启用无线调试
1. 在网络上搜索如何为您的机型启用“开发者选项”
2. 启用“开发者选项”和“USB 调试”<br><br><img :src="$withBase('/images/enable_dev_options.png')" style="max-width:320px;width:100%">
3. 进入“无线调试”<br><br><img :src="$withBase('/images/enter_wireless_debugging.png')" style="max-width:320px;width:100%">
4. 启用“无线调试”<br><br><img :src="$withBase('/images/enable_wireless_debugging.png')" style="max-width:320px;width:100%">
#### 配对(仅需一次)
1. 在 Shizuku 内开始配对<br><img :src="$withBase('/images/start_paring_from_shizuku.png')" style="max-width:320px;width:100%">
2. [启用无线调试](#启用无线调试)
3. 点按“无线调试”中的“使用配对码配对设备”<br><img :src="$withBase('/images/start_pairing.png')" style="max-width:320px;width:100%">
4. 在 Shizuku 的通知中填入配对码<br><img :src="$withBase('/images/enter_pairing_code.png')" style="max-width:320px;width:100%">
#### 启动 Shizuku
<img :src="$withBase('/images/start_shizuku.png')" style="max-width:320px;width:100%">
如果无法启动,尝试禁用并启用无线调试。
### 通过连接电脑启动
该启动方式适用于未 root 且运行 Android 10 及以下版本的设备。很不幸,该启动方式需要连接电脑。由于系统限制,每次重新启动后都需要再次进行启动步骤。
#### 什么是 `adb`?
Android 调试桥 (`adb`) 是一个通用命令行工具,其允许您与模拟器实例或连接的 Android 设备进行通信。它可为各种设备操作提供便利,如安装和调试应用,并提供对 Unix shell(可用来在模拟器或连接的设备上运行各种命令)的访问。
更多信息请查看 [Android Developer](https://developer.android.google.cn/studio/command-line/adb)。
#### 安装 `adb`
1. 下载由 Google 提供的“SDK 平台工具”并解压至任意文件夹
* [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)
* [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)
* [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)
2. 打开文件夹,右键选择
* Windows 10:在此处打开 PowerShell 窗口(**需要按住 Shift 才会显示该选项**)
* Windows 7:在此处打开命令行窗口(**需要按住 Shift 才会显示该选项**)
* Mac 或 Linux:打开 Terminal(终端)
3. 输入 `adb` 如果可以看到一长串内容而不是提示找不到 adb 则表示成功
::: tip 提示
1. 请不要关闭该窗口,后面提到的“终端”都是指此窗口(如果关闭请重新进行第 2 步)。
2. 如果使用 PowerShell 或是 Linux 及 Mac,所有 `adb` 都要替换成 `./adb`。
:::
#### 设置 `adb`
要使用 `adb` 你首先需要在设备上打开 USB 调试功能,通常需要经过以下步骤:
1. 打开系统设置,进入关于
2. 连续数次点击 "Build number" 后看到类似 "You are a developer" 的提示
3. 此时你应该可以在设置中找到“开发者选项”,进入后开启“USB 调试”
4. 连接设备到电脑,在终端中输入 `adb devices`
5. 此时设备上会出现“是否允许调试”的对话框,勾选“总是允许”后确认
6. 再次在终端中输入 `adb devices`,如无问题将会看到类似如下内容
```
List of devices attached
XXX device
```
::: tip
不同设备开启“开发者选项”的步骤可能有所不同,请自己搜索。
:::
#### 启动 Shizuku
复制指令并粘贴到终端中,如无问题你将会在 Shizuku 中看到已启动成功。
::: details 适用于 Shizuku v11.2.0+ 的指令
```
adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh
```
:::
## 常见问题
许多厂商对 Android 系统进行了修改,这会造成 Shizuku 无法正常工作。
### 通过无线调试启动:一直显示“正在搜索配对服务”
请允许 Shizuku 在后台运行。
搜索配对服务需要访问本地网络,许多厂商在应用不可见后立刻禁止应用访问网络。您可以在网络上搜索如何在您的设备上允许应用在后台运行。
### 通过无线调试启动:点击“输入配对码”后立刻提示失败
#### MIUI(小米、POCO)
在系统设置的“通知管理”-“通知显示设置”将通知样式切换为“原生样式”。
### 通过无线调试启动/通过连接电脑启动:adb 权限受限
#### MIUI(小米、POCO)
在“开发者选项”中开启“USB 调试(安全设置)”。**注意,这和“USB 调试”是两个分开的选项。**
#### ColorOS(OPPO & OnePlus)
在“开发者选项”中关闭“权限监控”。
#### Flyme(魅族)
在“开发者选项”中关闭“Flyme 支付保护”。
### 通过无线调试启动/通过连接电脑启动:Shizuku 随机停止
#### 所有设备
- 保证 Shizuku 可以在后台运行。
- 不要关闭“USB 调试”及“开发者选项”。
- 在“开发者选项”中将 USB 使用模式改为“仅充电”。
在 Android 8 上的选项是“选择 USB 配置”-“仅充电”。
在 Android 9 及以上版本上选项是“默认 USB 配置”-“不进行数据传输”。
- (Android 11+)启用“停用 adb 授权超时功能”选项
#### EMUI (华为)
在“开发者选项”中开启「“仅充电”模式下允许 ADB 调试选项」。
#### MIUI(小米、POCO)
不要使用“手机管家”的扫描功能,因为它会禁用开发者选项。
#### Sony
不要点击连接 USB 后弹出的对话框,因为这会导致 USB 使用模式发生变化。
### 通过 root 启动:无法开机启动
请允许 Shizuku 在后台运行。
================================================
FILE: shizuku/zh-hans/introduction.md
================================================
# 简介
Shizuku 可以帮助普通应用借助一个由 app_process 启动的 Java 进程直接以 adb 或 root 特权使用系统 API。
> Shizuku 这个名字来自[这里](https://www.pixiv.net/artworks/75508584)。
## Shizuku 为何而生?
Shizuku 的诞生主要有两大目的:
1. 提供一个方便地使用系统 API 的方式
2. 为部分只需要 adb 权限的应用开发提供便利
## Shizuku 与“传统”做法对比
### “传统”做法
以启用/禁用组件为例,一些需要 root 权限的应用直接在 `su` 中执行 `pm disable`。
1. 执行 `su`
2. 执行 `pm disable`
3. (pre-Pie) 使用 app_process 启动 Java 进程([参见此处](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm))
4. (Pie+) 执行原生程序 `cmd`([参见此处](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/))
5. 处理参数,通过 binder 与 system server 交互,处理结果输出文字结果
其中每个“执行”都意味着新进程建立,su 内部使用 socket 与 su daemon 交互,大量的时间和性能被消耗在这样的过程中。(部分设计不佳的应用甚至会每次执行指令都执行一次 `su`)
此类做法的缺点在于:
1. **极慢**
2. 需要处理文本来获取结果
3. 功能受制于可用的指令
4. 即使 adb 有足够权限,应用也需要 root 权限才可使用
### Shizuku 做法
Shizuku app 会引导用户使用 root 或是 adb 方式运行一个进程(Shizuku 服务进程)。
1. 应用进程启动时 Shizuku 服务进程发送 binder 至应用进程
2. 应用通过该 binder 与 Shizuku 服务进程交互,Shizuku 服务进程通过 binder 与 system server 交互
Shizuku 的优点在于:
1. 极小额外时间及性能消耗
2. 与直接调用 API 体验几乎一致(应用开发者只需添加少量代码)
================================================
FILE: shizuku/zh-hant/README.md
================================================
---
home: true
heroImage: /logo.png
actionText: 瞭解更多
actionLink: /zh-hant/introduction.html
features:
- title: 優雅地使用系統 API
details: 忘掉 root shell 吧,你可以「直接使用」需要高權限的 API。此外,Shizuku 比 shell 要快得多。
- title: 支援 adb 使用
details: 如果你的「需要 root 的程式」只需要 adb 權限,則可以使用 Shizuku 輕鬆地擴大用戶羣體。
- title: 節省時間
details: Shizuku 有詳細的文檔引導使用者,你只需要讓使用者安裝 Shizuku。
footer: Copyright © 2019 RikkaApps
---
### 就像是系統程序一樣簡單
```java
private static final IPackageManager PACKAGE_MANAGER = IPackageManager.Stub.asInterface(
new ShizukuBinderWrapper(SystemServiceHelper.getSystemService("package")));
public static void grantRuntimePermission(String packageName, String permissionName, int userId) {
try {
PACKAGE_MANAGER.grantRuntimePermission(packageName, permissionName, userId);
} catch (RemoteException tr) {
throw new RuntimeException(tr.getMessage(), tr);
}
}
```
::: tip
還有一些步驟要做,比如檢查權限或 Shizuku 是否正在執行。
:::
================================================
FILE: shizuku/zh-hant/download.md
================================================
# 下載
[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)
[GitHub Release](https://github.com/RikkaApps/Shizuku/releases)
[Coolapk](https://www.coolapk.com/apk/moe.shizuku.privileged.api)
[IzzyOnDroid F-Droid Repository](https://apt.izzysoft.de/fdroid/index/apk/moe.shizuku.privileged.api)
================================================
FILE: shizuku/zh-hant/guide/setup.md
================================================
# 使用者手冊
[[toc]]
## 啟動 Shizuku
Shizuku 支援透過以下三種方式啟動。
::: tip 如果您正在使用 GrapheneOS
您可能需要關閉 系統設定 - 「安全」 - 「Secure app spawning」。
[來源](https://github.com/RikkaApps/websites/pull/79#issue-1751837442)
:::
### 透過 root 啟動
對於已 root 裝置,直接啟動即可。
### 透過無線偵錯啟動
透過無線除錯啟動適用於 Android 11 或以上版本。這種啟動方式無需連線電腦。由於系統限制,每次重新啟動後都需要再次進行啟動步驟。
#### 啟用無線偵錯
1. 在網路上搜索如何為您的機型啟用「開發人員選項」
2. 啟用「開發人員選項」和「USB 偵錯」<br><br><img :src="$withBase('/images/enable_dev_options.png')" style="max-width:320px;width:100%">
3. 進入「無線偵錯」<br><br><img :src="$withBase('/images/enter_wireless_debugging.png')" style="max-width:320px;width:100%">
4. 啟用「無線偵錯」<br><br><img :src="$withBase('/images/enable_wireless_debugging.png')" style="max-width:320px;width:100%">
#### 配對(僅需一次)
1. 在 Shizuku 內開始配對<br><img :src="$withBase('/images/start_paring_from_shizuku.png')" style="max-width:320px;width:100%">
2. [啟用無線偵錯](#啟用無線偵錯)
3. 點按「無線偵錯」中的「使用配對碼配對裝置」<br><img :src="$withBase('/images/start_pairing.png')" style="max-width:320px;width:100%">
4. 在 Shizuku 的通知中填入配對碼<br><img :src="$withBase('/images/enter_pairing_code.png')" style="max-width:320px;width:100%">
#### 啟動 Shizuku
<img :src="$withBase('/images/start_shizuku.png')" style="max-width:320px;width:100%">
如果無法啟動,嘗試禁用並啟用無線偵錯。
### 透過連線電腦啟動
該啟動方式適用於未 root 且執行 Android 10 及以下版本的裝置。很不幸,該啟動方式需要連線電腦。由於系統限制,每次重新啟動後都需要再次進行啟動步驟。
#### 什麼是 `adb`?
Android 除錯橋 (`adb`) 是一個通用命令列工具,其允許您與模擬器例項或連線的 Android 裝置進行通訊。它可為各種裝置操作提供便利,如安裝和除錯程式,並提供對 Unix shell(可用來在模擬器或連線的裝置上執行各種命令)的存取。
更多資訊請檢視 [Android Developer](https://developer.android.com/studio/command-line/adb)。
#### 安裝 `adb`
1. 下載由 Google 提供的「SDK Platform Tools」並解壓至任意資料夾
* [Windows](https://dl.google.com/android/repository/platform-tools-latest-windows.zip)
* [Linux](https://dl.google.com/android/repository/platform-tools-latest-linux.zip)
* [Mac](https://dl.google.com/android/repository/platform-tools-latest-darwin.zip)
2. 開啟資料夾,右鍵選擇
* Windows 10:在此處開啟 PowerShell 視窗(**需要按住 Shift 才會顯示該選項**)
* Windows 7:在此處開啟命令視窗(**需要按住 Shift 才會顯示該選項**)
* Mac 或 Linux:打开 Terminal(終端)
3. 輸入 `adb` 如果可以看到一長串內容而不是提示找不到 adb 則表示成功
::: tip 提示
1. 請不要關閉該視窗,後面提到的「終端」都是指此視窗(如果關閉請重新進行第 2 步)。
2. 如果使用 PowerShell 或是 Linux 及 Mac,所有 `adb` 都要替換成 `./adb`。
:::
#### 設定 `adb`
要使用 `adb` 你首先需要在裝置上開啟 USB 偵錯功能,通常需要經過以下步驟:
1. 開啟系統設定,進入關於
2. 連續數次點選 "Build number" 後看到類似 "You are a developer" 的提示
3. 此時你應該可以在設定中找到「開發人員選項」,進入後開啟「USB 偵錯」
4. 連線裝置到電腦,在終端中輸入 `adb devices`
5. 此時裝置上會出現「是否允許偵錯」的對話方塊,勾選「總是允許」後確認
6. 再次在終端中輸入 `adb devices`,如無問題將會看到類似如下內容
```
List of devices attached
XXX device
```
::: tip
不同裝置開啟「開發人員選項」的步驟可能有所不同,請自己搜尋。
:::
#### 啟動 Shizuku
複製指令並貼上到終端中,如無問題你將會在 Shizuku 中看到已啟動成功。
::: details 適用於 Shizuku v11.2.0+ 的指令
```
adb shell sh /sdcard/Android/data/moe.shizuku.privileged.api/start.sh
```
:::
## 常見問題
許多廠商對 Android 系統進行了修改,這會造成 Shizuku 無法正常工作。
### 透過無線除錯啟動:一直顯示「正在搜尋配對服務」
請允許 Shizuku 在背景執行。
搜尋配對服務需要訪問本地網路,許多廠商在應用程式不可見後立刻禁止應用程式訪問網路。您可以在網路上搜索如何在您的裝置上允許應用程式在背景執行。
### 透過無線除錯啟動:點選「輸入配對碼」後立刻提示失敗
#### MIUI(Xiaomi、POCO)
在系統設定的「通知管理」-「通知顯示設定」將通知樣式切換為「Android」。
### 透過無線除錯啟動/透過連線電腦啟動:adb 權限受限
#### MIUI(Xiaomi、POCO)
在「開發人員選項」中開啟「USB 偵錯(安全設定)」。**注意,這和「USB 偵錯」是兩個分開的選項。**
#### ColorOS(OPPO & OnePlus)
你需要在「開發人員選項」中關閉「權限監控」。
#### Flyme(魅族)
你需要在「開發人員選項」中關閉「Flyme 支付保護」。
### 透過無線除錯啟動/透過連線電腦啟動:Shizuku 隨機停止
#### 所有裝置
- 保證 Shizuku 可以在背景執行。
- 不要關閉「USB 偵錯」及「開發人員選項」。
- 在「開發人員選項」中將 USB 使用模式改為「僅充電」。
在 Android 8 上的選項是「選擇 USB 配置」-「僅充電」。
在 Android 9 及以上版本上選項是「預設 USB 配置」-「不進行資料傳輸」。
- (Android 11+)啟用「停用 ADB 授權逾時」選項。
#### EMUI (Huawei)
你需要在「開發人員選項」中開啟「僅充電模式下允許 ADB 偵錯選項」。
#### MIUI(Xiaomi、POCO)
不要使用 MIUI 的「手機管家」的掃描功能,因為它會禁用「開發人員選項」。
#### Sony
不要點選連線 USB 後彈出的對話方塊,因為這會導致 USB 使用模式發生變化。
### 透過 root 啟動:無法開機啟動
請允許 Shizuku 在背景執行。
================================================
FILE: shizuku/zh-hant/introduction.md
================================================
# 簡介
Shizuku 可以幫助普通程式藉助一個由 app_process 啟動的 Java 程序直接以 adb 或 root 特權使用系統 API。
Shizuku 這個名字來自[這裡](https://www.pixiv.net/artworks/75508584)。
## Shizuku 為何而生?
Shizuku 的誕生主要有兩大目的:
1. 提供一個方便地使用系統 API 的方式
2. 為部分只需要 adb 許可權的程式開發提供便利
## Shizuku 與「傳統」做法對比
### 「傳統」做法
以啟用/停用元件為例,一些需要 root 許可權的程式直接在 `su` 中執行 `pm disable`。
1. 執行 `su`
2. 執行 `pm disable`
3. (pre-Pie) 使用 app_process 啟動 Java 程序([參見此處](https://android.googlesource.com/platform/frameworks/base/+/oreo-release/cmds/pm/pm))
4. (Pie+) 執行原生程式 `cmd`([參見此處](https://android.googlesource.com/platform/frameworks/native/+/pie-release/cmds/cmd/))
5. 處理引數,通過 binder 與 system server 互動,處理結果輸出文字結果
其中每個「執行」都意味著新程序建立,su 內部使用 socket 與 su daemon 互動,這樣的過程中消耗大量的時間和效能。(部分設計不佳的程式甚至會每次執行指令都執行一次 `su`)
此類做法的缺點在於:
1. **極慢**
2. 需要處理文字來獲取結果
3. 功能受制於可用的指令
4. 即使 adb 有足夠許可權,程式也需要 root 許可權才可使用
### Shizuku 做法
Shizuku app 會引導使用者使用 root 或是 adb 方式執行一個程序(Shizuku 服務程序)。
1. 應用程序啟動時 Shizuku 服務程序傳送 binder 至應用程序
2. 應用通過該 binder 與 Shizuku 服務程序互動,Shizuku 服務程序通過 binder 與 system server 互動
Shizuku 的優點在於:
1. 極小額外時間及效能消耗
2. 與直接呼叫 API 體驗幾乎一致(程式開發者只需新增少量程式碼)
================================================
FILE: storage_redirect/.gitignore
================================================
/.vuepress/dist
================================================
FILE: storage_redirect/.vuepress/config.js
================================================
const moment = require('moment')
const langMap = {
"zh-Hans": "zh-cn",
"zh-Hant": "zh-tw"
}
var timestampCache = {}
module.exports = {
base: '/',
title: 'Storage Isolation',
head: [
['link', {
rel: 'stylesheet',
href: 'https://fonts.googleapis.com/css?family=Roboto+Mono&display=swap',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://raw.rikka.app/css/SourceCodePro-BDC.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/Roboto-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-SC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', {
rel: 'stylesheet',
href: 'https://cdn.jsdelivr.net/gh/RikkaW/webfonts@4/css/NotoSansCJK-TC-VF.css',
media: 'print',
onload: "this.media='all'"
}],
['link', { rel: 'apple-touch-icon', size: '57x57', href: '/icon/apple-icon-57x57.png' }],
['link', { rel: 'apple-touch-icon', size: '60x60', href: '/icon/apple-icon-60x60.png' }],
['link', { rel: 'apple-touch-icon', size: '72x72', href: '/icon/apple-icon-72x72.png' }],
['link', { rel: 'apple-touch-icon', size: '76x76', href: '/icon/apple-icon-76x76.png' }],
['link', { rel: 'apple-touch-icon', size: '114x114', href: '/icon/apple-icon-114x114.png' }],
['link', { rel: 'apple-touch-icon', size: '120x120', href: '/icon/apple-icon-120x120.png' }],
['link', { rel: 'apple-touch-icon', size: '144x144', href: '/icon/apple-icon-144x144.png' }],
['link', { rel: 'apple-touch-icon', size: '152x152', href: '/icon/apple-icon-152x152.png' }],
['link', { rel: 'apple-touch-icon', size: '180x180', href: '/icon/apple-icon-180x180.png' }],
['link', { rel: 'icon', type: 'image/png', size: '192x192', href: '/icon/android-icon-192x192.png' }],
['link', { rel: 'icon', type: 'image/png', size: '32x32', href: '/icon/favicon-32x32.png' }],
['link', { rel: 'icon', type: 'image/png', size: '96x96', href: '/icon/favicon-96x96.png' }],
['link', { rel: 'icon', type: 'image/png', size: '16x16', href: '/icon/favicon-16x16.png' }]
],
locales: {
'/': {
lang: 'en',
description: 'Elegantly solve the problem of bad apps abusing storage permissions'
},
'/zh-hans/': {
lang: 'zh-Hans',
title: '存储空间隔离',
description: '优雅地解决“坏应用”滥用存储权限的问题'
},
'/zh-hant/': {
lang: 'zh-Hant',
title: '儲存空間隔離',
description: '優雅地解決「壞應用程式」濫用儲存權限的問題'
}
},
themeConfig: {
locales: {
'/': {
selectText: 'Languages',
label: 'English',
serviceWorker: {
updatePopup: {
message: "New content is available.",
buttonText: "Refresh"
}
},
sidebar: getSidebar('/guide/', 'Guide', 'Advanced', 'Enhanced mode', 'Issues caused by OEMs', 'FAQ'),
nav: getNavbar('/', 'Guide', 'Download', 'Changelog', 'Rikka Apps'),
lastUpdated: 'Last Updated'
},
'/zh-hans/': {
selectText: '语言',
label: '简体中文',
editLinkText: '在 GitHub 上编辑此页',
serviceWorker: {
updatePopup: {
message: "发现新内容可用.",
buttonText: "刷新"
}
},
sidebar: getSidebar('/zh-hans/guide/', '指南', '高级', '增强模式', '厂商造成的问题', 'FAQ'),
nav: getNavbar('/zh-hans/', '指南', '下载', 'Changelog', 'Rikka Apps'),
lastUpdated: '最后更新'
},
'/zh-hant/': {
selectText: '語言',
label: '繁體中文',
editLinkText: '在 GitHub 上編輯此頁',
serviceWorker: {
updatePopup: {
message: "發現新內容可用.",
buttonText: "重新整理"
}
},
sidebar: getSidebar('/zh-hant/guide/', '指南', '高級', '增強模式', '廠商造成的問題', 'FAQ'),
nav: getNavbar('/zh-hant/', '指南', '下載', 'Changelog', 'Rikka Apps'),
lastUpdated: '最後更新'
}
},
displayAllHeaders: true,
sidebarDepth: 2,
serviceWorker: {
updatePopup: true
},
docsRepo: 'https://github.com/RikkaApps/websites',
docsDir: 'storage_redirect',
editLinks: true
},
plugins: [
[
'sitemap',
{
hostname: 'https://sr.rikka.app',
exclude: ['/404.html'],
dateFormatter: (time) => {
timestampCache[time]
}
}
],
[
'clean-urls',
{
normalSuffix: '/',
indexSuffix: '/',
notFoundPath: '/404.html'
}
],
[
'@vuepress/last-updated',
{
transformer: (timestamp, lang) => {
var original = timestamp
moment.locale(langMap[lang])
var localized = moment(original).format('lll')
moment.locale('en')
var iso = moment(original).toISOString()
timestampCache[localized] = iso
return localized
}
}
]
]
}
function getSidebar(prefix, basicTitle, advancedTitle, enhancedModeTitle, compatibilityTitle, faqTitle) {
var res = {}
res[prefix] = [
{
title: basicTitle,
collapsable: true,
sidebarDepth: 0,
children: [
'',
'tutorial',
'contribute',
]
},
{
title: advancedTitle,
collapsable: true,
sidebarDepth: 0,
children: [
'advanced/shared_user_id',
'advanced/technical_details_export_isolated_files',
]
},
{
title: enhancedModeTitle,
collapsable: true,
sidebarDepth: 0,
children: [
`enhanced_mode/`,
`enhanced_mode/install`,
]
},
{
title: compatibilityTitle,
collapsable: true,
sidebarDepth: 0,
children: [
`compatibility/`,
`compatibility/samsung`,
`compatibility/meizu`,
`compatibility/miui`,
]
},
{
title: faqTitle,
collapsable: true,
sidebarDepth: 0,
children: [
`faq/cant_find_app`,
`faq/how_to_report_problems`,
`faq/how_to_document`,
]
}]
return res
}
function getNavbar(prefix, guide, download, changelog, allRikkaApps) {
return [
{ text: guide, link: `${prefix}guide/` },
{ text: download, link: `${prefix}download.html` },
{ text: changelog, link: `${prefix}changelog.html` },
{ text: allRikkaApps, link: `https://rikka.app${prefix}` },
]
}
================================================
FILE: storage_redirect/.vuepress/public/icon/browserconfig.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<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>
================================================
FILE: storage_redirect/.vuepress/public/icon/manifest.json
================================================
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}
================================================
FILE: storage_redirect/.vuepress/theme/LICENSE
================================================
The MIT License (MIT)
Copyright (c) 2018-present, Yuxi (Evan) You
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: storage_redirect/.vuepress/theme/components/AlgoliaSearchBox.vue
================================================
<template>
<form
id="search-form"
class="algolia-search-wrapper search-box"
role="search"
>
<input
id="algolia-search-input"
class="search-query"
:placeholder="placeholder"
>
</form>
</template>
<script>
export default {
props: ['options'],
data () {
return {
placeholder: undefined
}
},
mounted () {
this.initialize(this.options, this.$lang)
this.placeholder = this.$site.themeConfig.searchPlaceholder || ''
},
methods: {
initialize (userOptions, lang) {
Promise.all([
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.js'),
import(/* webpackChunkName: "docsearch" */ 'docsearch.js/dist/cdn/docsearch.min.css')
]).then(([docsearch]) => {
docsearch = docsearch.default
const { algoliaOptions = {}} = userOptions
docsearch(Object.assign(
{},
userOptions,
{
inputSelector: '#algolia-search-input',
// #697 Make docsearch work well at i18n mode.
algoliaOptions: Object.assign({
'facetFilters': [`lang:${lang}`].concat(algoliaOptions.facetFilters || [])
}, algoliaOptions),
handleSelected: (input, event, suggestion) => {
const { pathname, hash } = new URL(suggestion.url)
this.$router.push(`${pathname}${hash}`)
}
}
))
})
},
update (options, lang) {
this.$el.innerHTML = '<input id="algolia-search-input" class="search-query">'
this.initialize(options, lang)
}
},
watch: {
$lang (newValue) {
this.update(this.options, newValue)
},
options (newValue) {
this.update(newValue, this.$lang)
}
}
}
</script>
<style lang="stylus">
.algolia-search-wrapper
& > span
vertical-align middle
.algolia-autocomplete
line-height normal
.ds-dropdown-menu
background-color #fff
border 1px solid #999
border-radius 4px
font-size 16px
margin 6px 0 0
padding 4px
text-align left
&:before
border-color #999
[class*=ds-dataset-]
border none
padding 0
.ds-suggestions
margin-top 0
.ds-suggestion
border-bottom 1px solid $borderColor
.algolia-docsearch-suggestion--highlight
color #2c815b
.algolia-docsearch-suggestion
border-color $borderColor
padding 0
.algolia-docsearch-suggestion--category-header
padding 5px 10px
margin-top 0
background $accentColor
color #fff
font-weight 600
.algolia-docsearch-suggestion--highlight
background rgba(255, 255, 255, 0.6)
.algolia-docsearch-suggestion--wrapper
padding 0
.algolia-docsearch-suggestion--title
font-weight 600
margin-bottom 0
color $textColor
.algolia-docsearch-suggestion--subcategory-column
vertical-align top
padding 5px 7px 5px 5px
border-color $borderColor
background #f1f3f5
&:after
display none
.algolia-docsearch-suggestion--subcategory-column-text
color #555
.algolia-docsearch-footer
border-color $borderColor
.ds-cursor .algolia-docsearch-suggestion--content
background-color #e7edf3 !important
color $textColor
@media (min-width: $MQMobile)
.algolia-search-wrapper
.algolia-autocomplete
.algolia-docsearch-suggestion
.algolia-docsearch-suggestion--subcategory-column
float none
width 150px
min-width 150px
display table-cell
.algolia-docsearch-suggestion--content
float none
display table-cell
width 100%
vertical-align top
.ds-dropdown-menu
min-width 515px !important
@media (max-width: $MQMobile)
.algolia-search-wrapper
.ds-dropdown-menu
min-width calc(100vw - 4rem) !important
max-width calc(100vw - 4rem) !important
.algolia-docsearch-suggestion--wrapper
padding 5px 7px 5px 5px !important
.algolia-docsearch-suggestion--subcategory-column
padding 0 !important
background white !important
.algolia-docsearch-suggestion--subcategory-column-text:after
content " > "
font-size 10px
line-height 14.4px
display inline-block
width 5px
margin -3px 3px 0
vertical-align middle
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/Download.vue
================================================
<template>
<main class="download">
</main>
</template>
<script>
export default {
computed: {
data() {
return this.$page.frontmatter;
}
}
};
</script>
================================================
FILE: storage_redirect/.vuepress/theme/components/DropdownLink.vue
================================================
<template>
<div
class="dropdown-wrapper"
:class="{ open }"
>
<a
class="dropdown-title"
@click="toggle"
>
<span class="title">{{ item.text }}</span>
<span
class="arrow"
:class="open ? 'down' : 'right'"
></span>
</a>
<DropdownTransition>
<ul
class="nav-dropdown"
v-show="open"
>
<li
class="dropdown-item"
:key="subItem.link || index"
v-for="(subItem, index) in item.items"
>
<h4 v-if="subItem.type === 'links'">{{ subItem.text }}</h4>
<ul
class="dropdown-subitem-wrapper"
v-if="subItem.type === 'links'"
>
<li
class="dropdown-subitem"
:key="childSubItem.link"
v-for="childSubItem in subItem.items"
>
<NavLink :item="childSubItem"/>
</li>
</ul>
<NavLink
v-else
:item="subItem"
/>
</li>
</ul>
</DropdownTransition>
</div>
</template>
<script>
import NavLink from '@theme/components/NavLink.vue'
import DropdownTransition from '@theme/components/DropdownTransition.vue'
export default {
components: { NavLink, DropdownTransition },
data () {
return {
open: false
}
},
props: {
item: {
required: true
}
},
methods: {
toggle () {
this.open = !this.open
}
}
}
</script>
<style lang="stylus">
.dropdown-wrapper
cursor pointer
.dropdown-title
display block
&:hover
border-color transparent
.arrow
vertical-align middle
margin-top -1px
margin-left 0.4rem
.nav-dropdown
.dropdown-item
color inherit
line-height 1.7rem
h4
margin 0.45rem 0 0
border-top 1px solid #eee
padding 0.45rem 1.5rem 0 1.25rem
.dropdown-subitem-wrapper
padding 0
list-style none
.dropdown-subitem
font-size 0.9em
a
display block
line-height 1.7rem
position relative
border-bottom none
font-weight 400
margin-bottom 0
padding 0 1.5rem 0 1.25rem
&:hover
color $accentColor
&.router-link-active
color $accentColor
&::after
content ""
width 0
height 0
border-left 5px solid $accentColor
border-top 3px solid transparent
border-bottom 3px solid transparent
position absolute
top calc(50% - 2px)
left 9px
&:first-child h4
margin-top 0
padding-top 0
border-top 0
@media (max-width: $MQMobile)
.dropdown-wrapper
&.open .dropdown-title
margin-bottom 0.5rem
.nav-dropdown
transition height .1s ease-out
overflow hidden
.dropdown-item
h4
border-top 0
margin-top 0
padding-top 0
h4, & > a
font-size 15px
line-height 2rem
.dropdown-subitem
font-size 14px
padding-left 1rem
@media (min-width: $MQMobile)
.dropdown-wrapper
height 1.8rem
&:hover .nav-dropdown
// override the inline style.
display block !important
.dropdown-title .arrow
// make the arrow always down at desktop
border-left 4px solid transparent
border-right 4px solid transparent
border-top 6px solid $arrowBgColor
border-bottom 0
.nav-dropdown
display none
// Avoid height shaked by clicking
height auto !important
box-sizing border-box;
max-height calc(100vh - 2.7rem)
overflow-y auto
position absolute
top 100%
right 0
background-color #fff
padding 0.6rem 0
border 1px solid #ddd
border-bottom-color #ccc
text-align left
border-radius 0.25rem
white-space nowrap
margin 0
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/DropdownTransition.vue
================================================
<template>
<transition
name="dropdown"
@enter="setHeight"
@after-enter="unsetHeight"
@before-leave="setHeight"
>
<slot/>
</transition>
</template>
<script>
export default {
name: 'DropdownTransition',
methods: {
setHeight (items) {
// explicitly set height so that it can be transitioned
items.style.height = items.scrollHeight + 'px'
},
unsetHeight (items) {
items.style.height = ''
}
}
}
</script>
<style lang="stylus">
.dropdown-enter, .dropdown-leave-to
height 0 !important
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/Home.vue
================================================
<template>
<main class="home" aria-labelledby="main-title">
<header class="hero">
<img
v-if="data.heroImage"
:src="$withBase(data.heroImage)"
:alt="data.heroAlt || 'hero'"
>
<h1 v-if="data.heroText !== null" id="main-title">{{ data.heroText || $title || 'Hello' }}</h1>
<p class="description">
{{ data.tagline || $description || 'Welcome to your VuePress site' }}
</p>
<div class="actions">
<div
class="action"
v-if="data.secondaryActionText && data.secondaryActionLink"
>
<NavLink
class="action-button secondary"
:item="secondaryActionLink"
/>
</div>
<div
class="action"
v-if="data.actionText && data.actionLink"
>
<NavLink
class="action-button"
:item="actionLink"
/>
</div>
</div>
</header>
<div
class="features"
v-if="data.features && data.features.length"
>
<div
class="feature"
v-for="(feature, index) in data.features"
:key="index"
>
<h2>{{ feature.title }}</h2>
<p>{{ feature.details }}</p>
</div>
</div>
<Content class="theme-default-content custom"/>
<div
class="footer"
v-if="data.footer"
>
{{ data.footer }}
</div>
</main>
</template>
<script>
import NavLink from '@theme/components/NavLink.vue'
export default {
components: { NavLink },
computed: {
data () {
return this.$page.frontmatter
},
actionLink () {
return {
link: this.data.actionLink,
text: this.data.actionText
}
},
secondaryActionLink () {
return {
link: this.data.secondaryActionLink,
text: this.data.secondaryActionText
}
}
}
}
</script>
<style lang="stylus">
.home
padding $navbarHeight 2rem 0
max-width 960px
margin 0px auto
display block
.hero
text-align center
img
max-width: 100%
max-height 280px
display block
margin 3rem auto 1.5rem
h1
font-size 3rem
h1, .description, .actions
margin 1.8rem auto
.description
max-width 35rem
font-size 1.6rem
line-height 1.3
color lighten($textColor, 40%)
.action
margin 0.6rem
.actions
display flex
flex-wrap wrap
align-items flex-start
align-content stretch
justify-content center
.action-button
display inline-block
font-size 1.2rem
color #fff
background-color $accentColor
padding 0.8rem 1.6rem
border-radius 4px
transition background-color .1s ease
box-sizing border-box
border-bottom 1px solid darken($accentColor, 10%)
&:hover
background-color lighten($accentColor, 10%)
.secondary
color $textColor
background-color #fff
transition background-color .1s ease
border 1px solid darken($textColor, 10%)
&:hover
background-color lighten($textColor, 90%)
.features
border-top 1px solid $borderColor
padding 1.2rem 0
margin-top 2.5rem
display flex
flex-wrap wrap
align-items flex-start
align-content stretch
justify-content space-between
.feature
flex-grow 1
flex-basis 30%
max-width 30%
h2
font-size 1.4rem
font-weight 500
border-bottom none
padding-bottom 0
color lighten($textColor, 10%)
p
color lighten($textColor, 25%)
.footer
padding 2.5rem
border-top 1px solid $borderColor
text-align center
color lighten($textColor, 25%)
@media (max-width: $MQMobile)
.home
.features
flex-direction column
.feature
max-width 100%
padding 0 2.5rem
@media (max-width: $MQMobileNarrow)
.home
padding-left 1.5rem
padding-right 1.5rem
.hero
img
max-height 210px
margin 2rem auto 1.2rem
h1
font-size 2rem
h1, .description, .actions
margin 1.2rem auto
.description
font-size 1.2rem
.action-button
font-size 1rem
padding 0.6rem 1.2rem
.feature
h2
font-size 1.25rem
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/NavLink.vue
================================================
<template>
<router-link
class="nav-link"
:to="link"
v-if="!isExternal(link)"
:exact="exact"
>{{ item.text }}</router-link>
<a
v-else
:href="link"
class="nav-link external"
:target="isMailto(link) || isTel(link) ? null : '_blank'"
:rel="isMailto(link) || isTel(link) ? null : 'noopener noreferrer'"
>
{{ item.text }}
<OutboundLink/>
</a>
</template>
<script>
import { isExternal, isMailto, isTel, ensureExt } from '../util'
export default {
props: {
item: {
required: true
}
},
computed: {
link () {
return ensureExt(this.item.link)
},
exact () {
if (this.$site.locales) {
return Object.keys(this.$site.locales).some(rootLink => rootLink === this.link)
}
return this.link === '/'
}
},
methods: {
isExternal,
isMailto,
isTel
}
}
</script>
================================================
FILE: storage_redirect/.vuepress/theme/components/NavLinks.vue
================================================
<template>
<nav
class="nav-links"
v-if="userLinks.length || repoLink"
>
<!-- user links -->
<div
class="nav-item"
v-for="item in userLinks"
:key="item.link"
>
<DropdownLink
v-if="item.type === 'links'"
:item="item"
/>
<NavLink
v-else
:item="item"
/>
</div>
<!-- repo link -->
<a
v-if="repoLink"
:href="repoLink"
class="repo-link"
target="_blank"
rel="noopener noreferrer"
>
{{ repoLabel }}
<OutboundLink/>
</a>
</nav>
</template>
<script>
import DropdownLink from '@theme/components/DropdownLink.vue'
import { resolveNavLinkItem } from '../util'
import NavLink from '@theme/components/NavLink.vue'
export default {
components: { NavLink, DropdownLink },
computed: {
userNav () {
return this.$themeLocaleConfig.nav || this.$site.themeConfig.nav || []
},
nav () {
const { locales } = this.$site
if (locales && Object.keys(locales).length > 1) {
const currentLink = this.$page.path
const routes = this.$router.options.routes
const themeLocales = this.$site.themeConfig.locales || {}
const languageDropdown = {
text: this.$themeLocaleConfig.selectText || 'Languages',
items: Object.keys(locales).map(path => {
const locale = locales[path]
const text = themeLocales[path] && themeLocales[path].label || locale.lang
let link
// Stay on the current page
if (locale.lang === this.$lang) {
link = currentLink
} else {
// Try to stay on the same page
link = currentLink.replace(this.$localeConfig.path, path)
// fallback to homepage
if (!routes.some(route => route.path === link)) {
link = path
}
}
return { text, link }
})
}
return [...this.userNav, languageDropdown]
}
return this.userNav
},
userLinks () {
return (this.nav || []).map(link => {
return Object.assign(resolveNavLinkItem(link), {
items: (link.items || []).map(resolveNavLinkItem)
})
})
},
repoLink () {
const { repo } = this.$site.themeConfig
if (repo) {
return /^https?:/.test(repo)
? repo
: `https://github.com/${repo}`
}
},
repoLabel () {
if (!this.repoLink) return
if (this.$site.themeConfig.repoLabel) {
return this.$site.themeConfig.repoLabel
}
const repoHost = this.repoLink.match(/^https?:\/\/[^/]+/)[0]
const platforms = ['GitHub', 'GitLab', 'Bitbucket']
for (let i = 0; i < platforms.length; i++) {
const platform = platforms[i]
if (new RegExp(platform, 'i').test(repoHost)) {
return platform
}
}
return 'Source'
}
}
}
</script>
<style lang="stylus">
.nav-links
display inline-block
a
line-height 1.4rem
color inherit
&:hover, &.router-link-active
color $accentColor
.nav-item
position relative
display inline-block
margin-left 1.5rem
line-height 2rem
&:first-child
margin-left 0
.repo-link
margin-left 1.5rem
@media (max-width: $MQMobile)
.nav-links
.nav-item, .repo-link
margin-left 0
@media (min-width: $MQMobile)
.nav-links a
&:hover, &.router-link-active
color $textColor
.nav-item > a:not(.external)
&:hover, &.router-link-active
margin-bottom -2px
border-bottom 2px solid lighten($accentColor, 8%)
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/Navbar.vue
================================================
<template>
<header class="navbar">
<SidebarButton @toggle-sidebar="$emit('toggle-sidebar')"/>
<router-link
:to="$localePath"
class="home-link"
>
<img
class="logo"
v-if="$site.themeConfig.logo"
:src="$withBase($site.themeConfig.logo)"
:alt="$siteTitle"
>
<span
ref="siteName"
class="site-name"
v-if="$siteTitle"
:class="{ 'can-hide': $site.themeConfig.logo }"
>{{ $siteTitle }}</span>
</router-link>
<div
class="links"
:style="linksWrapMaxWidth ? {
'max-width': linksWrapMaxWidth + 'px'
} : {}"
>
<AlgoliaSearchBox
v-if="isAlgoliaSearch"
:options="algolia"
/>
<SearchBox v-else-if="$site.themeConfig.search !== false && $page.frontmatter.search !== false"/>
<NavLinks class="can-hide"/>
</div>
</header>
</template>
<script>
import AlgoliaSearchBox from '@AlgoliaSearchBox'
import SearchBox from '@SearchBox'
import SidebarButton from '@theme/components/SidebarButton.vue'
import NavLinks from '@theme/components/NavLinks.vue'
export default {
components: { SidebarButton, NavLinks, SearchBox, AlgoliaSearchBox },
data () {
return {
linksWrapMaxWidth: null
}
},
mounted () {
const MOBILE_DESKTOP_BREAKPOINT = 719 // refer to config.styl
const NAVBAR_VERTICAL_PADDING = parseInt(css(this.$el, 'paddingLeft')) + parseInt(css(this.$el, 'paddingRight'))
const handleLinksWrapWidth = () => {
if (document.documentElement.clientWidth < MOBILE_DESKTOP_BREAKPOINT) {
this.linksWrapMaxWidth = null
} else {
this.linksWrapMaxWidth = this.$el.offsetWidth - NAVBAR_VERTICAL_PADDING
- (this.$refs.siteName && this.$refs.siteName.offsetWidth || 0)
}
}
handleLinksWrapWidth()
window.addEventListener('resize', handleLinksWrapWidth, false)
},
computed: {
algolia () {
return this.$themeLocaleConfig.algolia || this.$site.themeConfig.algolia || {}
},
isAlgoliaSearch () {
return this.algolia && this.algolia.apiKey && this.algolia.indexName
}
}
}
function css (el, property) {
// NOTE: Known bug, will return 'auto' if style value is 'auto'
const win = el.ownerDocument.defaultView
// null means not to return pseudo styles
return win.getComputedStyle(el, null)[property]
}
</script>
<style lang="stylus">
$navbar-vertical-padding = 0.7rem
$navbar-horizontal-padding = 1.5rem
.navbar
padding $navbar-vertical-padding $navbar-horizontal-padding
line-height $navbarHeight - 1.4rem
a, span, img
display inline-block
.logo
height $navbarHeight - 1.4rem
min-width $navbarHeight - 1.4rem
margin-right 0.8rem
vertical-align top
.site-name
font-size 1.3rem
font-weight 600
color $textColor
position relative
.links
padding-left 1.5rem
box-sizing border-box
background-color white
white-space nowrap
font-size 0.9rem
position absolute
right $navbar-horizontal-padding
top $navbar-vertical-padding
display flex
.search-box
flex: 0 0 auto
vertical-align top
@media (max-width: $MQMobile)
.navbar
padding-left 4rem
.can-hide
display none
.links
padding-left 1.5rem
.site-name
width calc(100vw - 9.4rem)
overflow hidden
white-space nowrap
text-overflow ellipsis
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/Page.vue
================================================
<template>
<main class="page">
<slot name="top" />
<Content class="theme-default-content" />
<PageEdit />
<PageNav v-bind="{ sidebarItems }" />
<slot name="bottom" />
</main>
</template>
<script>
import PageEdit from '@theme/components/PageEdit.vue'
import PageNav from '@theme/components/PageNav.vue'
export default {
components: { PageEdit, PageNav },
props: ['sidebarItems']
}
</script>
<style lang="stylus">
@require '../styles/wrapper.styl';
.page {
padding-bottom: 2rem;
display: block;
}
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/PageEdit.vue
================================================
<template>
<footer class="page-edit">
<div class="edit-link" v-if="editLink">
<a :href="editLink" target="_blank" rel="noopener noreferrer">{{ editLinkText }}</a>
<OutboundLink />
</div>
<div class="last-updated" v-if="lastUpdated">
<span class="prefix">{{ lastUpdatedText }}:</span>
<span class="time">{{ lastUpdated }}</span>
</div>
</footer>
</template>
<script>
import { endingSlashRE, outboundRE } from '../util'
export default {
name: 'PageEdit',
computed: {
lastUpdated () {
return this.$page.lastUpdated
},
lastUpdatedText () {
if (typeof this.$themeLocaleConfig.lastUpdated === 'string') {
return this.$themeLocaleConfig.lastUpdated
}
if (typeof this.$site.themeConfig.lastUpdated === 'string') {
return this.$site.themeConfig.lastUpdated
}
return 'Last Updated'
},
editLink () {
if (this.$page.frontmatter.editLink === false) {
return
}
const {
repo,
editLinks,
docsDir = '',
docsBranch = 'master',
docsRepo = repo
} = this.$site.themeConfig
if (docsRepo && editLinks && this.$page.relativePath) {
return this.createEditLink(
repo,
docsRepo,
docsDir,
docsBranch,
this.$page.relativePath
)
}
},
editLinkText () {
return (
this.$themeLocaleConfig.editLinkText
|| this.$site.themeConfig.editLinkText
|| `Edit this page`
)
}
},
methods: {
createEditLink (repo, docsRepo, docsDir, docsBranch, path) {
const bitbucket = /bitbucket.org/
if (bitbucket.test(repo)) {
const base = outboundRE.test(docsRepo) ? docsRepo : repo
return (
base.replace(endingSlashRE, '')
+ `/src`
+ `/${docsBranch}/`
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')
+ path
+ `?mode=edit&spa=0&at=${docsBranch}&fileviewer=file-view-default`
)
}
const base = outboundRE.test(docsRepo)
? docsRepo
: `https://github.com/${docsRepo}`
return (
base.replace(endingSlashRE, '')
+ `/edit`
+ `/${docsBranch}/`
+ (docsDir ? docsDir.replace(endingSlashRE, '') + '/' : '')
+ path
)
}
}
}
</script>
<style lang="stylus">
@require '../styles/wrapper.styl';
.page-edit {
@extend $wrapper;
padding-top: 1rem;
padding-bottom: 1rem;
overflow: auto;
.edit-link {
display: inline-block;
a {
color: lighten($textColor, 25%);
margin-right: 0.25rem;
}
}
.last-updated {
float: right;
font-size: 0.9em;
.prefix {
font-weight: 500;
color: lighten($textColor, 25%);
}
.time {
font-weight: 400;
color: #aaa;
}
}
}
@media (max-width: $MQMobile) {
.page-edit {
.edit-link {
margin-bottom: 0.5rem;
}
.last-updated {
font-size: 0.8em;
float: none;
text-align: left;
}
}
}
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/PageNav.vue
================================================
<template>
<div class="page-nav" v-if="prev || next">
<p class="inner">
<span v-if="prev" class="prev">
←
<router-link v-if="prev" class="prev" :to="prev.path">{{ prev.title || prev.path }}</router-link>
</span>
<span v-if="next" class="next">
<router-link v-if="next" :to="next.path">{{ next.title || next.path }}</router-link>→
</span>
</p>
</div>
</template>
<script>
import { resolvePage } from '../util'
import isString from 'lodash/isString'
import isNil from 'lodash/isNil'
export default {
name: 'PageNav',
props: ['sidebarItems'],
computed: {
prev () {
return resolvePageLink(LINK_TYPES.PREV, this)
},
next () {
return resolvePageLink(LINK_TYPES.NEXT, this)
}
}
}
function resolvePrev (page, items) {
return find(page, items, -1)
}
function resolveNext (page, items) {
return find(page, items, 1)
}
const LINK_TYPES = {
NEXT: {
resolveLink: resolveNext,
getThemeLinkConfig: ({ nextLinks }) => nextLinks,
getPageLinkConfig: ({ frontmatter }) => frontmatter.next
},
PREV: {
resolveLink: resolvePrev,
getThemeLinkConfig: ({ prevLinks }) => prevLinks,
getPageLinkConfig: ({ frontmatter }) => frontmatter.prev
}
}
function resolvePageLink (
linkType,
{ $themeConfig, $page, $route, $site, sidebarItems }
) {
const { resolveLink, getThemeLinkConfig, getPageLinkConfig } = linkType
// Get link config from theme
const themeLinkConfig = getThemeLinkConfig($themeConfig)
// Get link config from current page
const pageLinkConfig = getPageLinkConfig($page)
// Page link config will overwrite global theme link config if defined
const link = isNil(pageLinkConfig) ? themeLinkConfig : pageLinkConfig
if (link === false) {
return
} else if (isString(link)) {
return resolvePage($site.pages, link, $route.path)
} else {
return resolveLink($page, sidebarItems)
}
}
function find (page, items, offset) {
const res = []
flatten(items, res)
for (let i = 0; i < res.length; i++) {
const cur = res[i]
if (cur.type === 'page' && cur.path === decodeURIComponent(page.path)) {
return res[i + offset]
}
}
}
function flatten (items, res) {
for (let i = 0, l = items.length; i < l; i++) {
if (items[i].type === 'group') {
flatten(items[i].children || [], res)
} else {
res.push(items[i])
}
}
}
</script>
<style lang="stylus">
@require '../styles/wrapper.styl';
.page-nav {
@extend $wrapper;
padding-top: 1rem;
padding-bottom: 0;
.inner {
min-height: 2rem;
margin-top: 0;
border-top: 1px solid $borderColor;
padding-top: 1rem;
overflow: auto; // clear float
}
.next {
float: right;
}
}
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/Sidebar.vue
================================================
<template>
<aside class="sidebar">
<NavLinks/>
<slot name="top"/>
<SidebarLinks :depth="0" :items="items"/>
<slot name="bottom"/>
</aside>
</template>
<script>
import SidebarLinks from '@theme/components/SidebarLinks.vue'
import NavLinks from '@theme/components/NavLinks.vue'
export default {
name: 'Sidebar',
components: { SidebarLinks, NavLinks },
props: ['items']
}
</script>
<style lang="stylus">
.sidebar
ul
padding 0
margin 0
list-style-type none
a
display inline-block
.nav-links
display none
border-bottom 1px solid $borderColor
padding 0.5rem 0 0.75rem 0
a
font-weight 600
.nav-item, .repo-link
display block
line-height 1.25rem
font-size 1.1em
padding 0.5rem 0 0.5rem 1.5rem
& > .sidebar-links
padding 1.5rem 0
& > li > a.sidebar-link
font-size 1.1em
line-height 1.7
font-weight bold
& > li:not(:first-child)
margin-top .75rem
@media (max-width: $MQMobile)
.sidebar
.nav-links
display block
.dropdown-wrapper .nav-dropdown .dropdown-item a.router-link-active::after
top calc(1rem - 2px)
& > .sidebar-links
padding 1rem 0
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/SidebarButton.vue
================================================
<template>
<div class="sidebar-button" @click="$emit('toggle-sidebar')">
<svg class="icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512">
<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>
</svg>
</div>
</template>
<style lang="stylus">
.sidebar-button
cursor pointer
display none
width 1.25rem
height 1.25rem
position absolute
padding 0.6rem
top 0.6rem
left 1rem
.icon
display block
width 1.25rem
height 1.25rem
@media (max-width: $MQMobile)
.sidebar-button
display block
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/SidebarGroup.vue
================================================
<template>
<section
class="sidebar-group"
:class="[
{
collapsable,
'is-sub-group': depth !== 0
},
`depth-${depth}`
]"
>
<router-link
v-if="item.path"
class="sidebar-heading clickable"
:class="{
open,
'active': isActive($route, item.path)
}"
:to="item.path"
@click.native="$emit('toggle')"
>
<span>{{ item.title }}</span>
<span
class="arrow"
v-if="collapsable"
:class="open ? 'down' : 'right'">
</span>
</router-link>
<p
v-else
class="sidebar-heading"
:class="{ open }"
@click="$emit('toggle')"
>
<span>{{ item.title }}</span>
<span
class="arrow"
v-if="collapsable"
:class="open ? 'down' : 'right'">
</span>
</p>
<DropdownTransition>
<SidebarLinks
class="sidebar-group-items"
:items="item.children"
v-if="open || !collapsable"
:sidebarDepth="item.sidebarDepth"
:depth="depth + 1"
/>
</DropdownTransition>
</section>
</template>
<script>
import { isActive } from '../util'
import DropdownTransition from '@theme/components/DropdownTransition.vue'
export default {
name: 'SidebarGroup',
props: ['item', 'open', 'collapsable', 'depth'],
components: { DropdownTransition },
// ref: https://vuejs.org/v2/guide/components-edge-cases.html#Circular-References-Between-Components
beforeCreate () {
this.$options.components.SidebarLinks = require('./SidebarLinks.vue').default
},
methods: { isActive }
}
</script>
<style lang="stylus">
.sidebar-group
.sidebar-group
padding-left 0.5em
&:not(.collapsable)
.sidebar-heading:not(.clickable)
cursor auto
color inherit
// refine styles of nested sidebar groups
&.is-sub-group
padding-left 0
& > .sidebar-heading
font-size 0.95em
line-height 1.4
font-weight normal
padding-left 2rem
&:not(.clickable)
opacity 0.5
& > .sidebar-group-items
padding-left 1rem
& > li > .sidebar-link
font-size: 0.95em;
border-left none
&.depth-2
& > .sidebar-heading
border-left none
.sidebar-heading
color $textColor
transition color .15s ease
cursor pointer
font-size 1.1em
font-weight bold
// text-transform uppercase
padding 0.35rem 1.5rem 0.35rem 1.25rem
width 100%
box-sizing border-box
margin 0
border-left 0.25rem solid transparent
&.open, &:hover
color inherit
.arrow
position relative
top -0.12em
left 0.5em
&.clickable
&.active
font-weight 600
color $accentColor
border-left-color $accentColor
&:hover
color $accentColor
.sidebar-group-items
transition height .1s ease-out
font-size 0.95em
overflow hidden
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/SidebarLink.vue
================================================
<script>
import { isActive, hashRE, groupHeaders } from '@theme/util'
export default {
functional: true,
props: ['item', 'sidebarDepth'],
render (h,
{
parent: {
$page,
$site,
$route,
$themeConfig,
$themeLocaleConfig
},
props: {
item,
sidebarDepth
}
}) {
// use custom active class matching logic
// due to edge case of paths ending with / + hash
const selfActive = isActive($route, item.path)
// for sidebar: auto pages, a hash link should be active if one of its child
// matches
const active = item.type === 'auto'
? selfActive || item.children.some(c => isActive($route, item.basePath + '#' + c.slug))
: selfActive
const link = item.type === 'external'
? renderExternal(h, item.path, item.title || item.path)
: renderLink(h, item.path, item.title || item.path, active)
const maxDepth = [
$page.frontmatter.sidebarDepth,
sidebarDepth,
$themeLocaleConfig.sidebarDepth,
$themeConfig.sidebarDepth,
1
].find(depth => depth !== undefined);
const displayAllHeaders = $themeLocaleConfig.displayAllHeaders
|| $themeConfig.displayAllHeaders
if (item.type === 'auto') {
return [link, renderChildren(h, item.children, item.basePath, $route, maxDepth)]
} else if ((active || displayAllHeaders) && item.headers && !hashRE.test(item.path)) {
const children = groupHeaders(item.headers)
return [link, renderChildren(h, children, item.path, $route, maxDepth)]
} else {
return link
}
}
}
function renderLink (h, to, text, active) {
return h('router-link', {
props: {
to,
activeClass: '',
exactActiveClass: ''
},
class: {
active,
'sidebar-link': true
}
}, text)
}
function renderChildren (h, children, path, route, maxDepth, depth = 1) {
if (!children || depth > maxDepth) return null
return h('ul', { class: 'sidebar-sub-headers' }, children.map(c => {
const active = isActive(route, path + '#' + c.slug)
return h('li', { class: 'sidebar-sub-header' }, [
renderLink(h, path + '#' + c.slug, c.title, active),
renderChildren(h, c.children, path, route, maxDepth, depth + 1)
])
}))
}
function renderExternal (h, to, text) {
return h('a', {
attrs: {
href: to,
target: '_blank',
rel: 'noopener noreferrer'
},
class: {
'sidebar-link': true
}
}, [text, h('OutboundLink')])
}
</script>
<style lang="stylus">
.sidebar .sidebar-sub-headers
padding-left 1rem
font-size 0.95em
a.sidebar-link
font-size 1em
font-weight 400
display inline-block
color $textColor
border-left 0.25rem solid transparent
padding 0.35rem 1rem 0.35rem 1.25rem
line-height 1.4
width: 100%
box-sizing: border-box
&:hover
color $accentColor
&.active
font-weight 600
color $accentColor
border-left-color $accentColor
.sidebar-group &
padding-left 2rem
.sidebar-sub-headers &
padding-top 0.25rem
padding-bottom 0.25rem
border-left none
&.active
font-weight 500
</style>
================================================
FILE: storage_redirect/.vuepress/theme/components/SidebarLinks.vue
================================================
<template>
<ul
class="sidebar-links"
v-if="items.length"
>
<li v-for="(item, i) in items" :key="i">
<SidebarGroup
v-if="item.type === 'group'"
:item="item"
:open="i === openGroupIndex"
:collapsable="item.collapsable || item.collapsible"
:depth="depth"
@toggle="toggleGroup(i)"
/>
<SidebarLink
v-else
:sidebarDepth="sidebarDepth"
:item="item"
/>
</li>
</ul>
</template>
<script>
import SidebarGroup from '@theme/components/SidebarGroup.vue'
import SidebarLink from '@theme/components/SidebarLink.vue'
import { isActive } from '../util'
export default {
name: 'SidebarLinks',
components: { SidebarGroup, SidebarLink },
props: [
'items',
'depth', // depth of current sidebar links
'sidebarDepth' // depth of headers to be extracted
],
data () {
return {
openGroupIndex: 0
}
},
created () {
this.refreshIndex()
},
watch: {
'$route' () {
this.refreshIndex()
}
},
methods: {
refreshIndex () {
const index = resolveOpenGroupIndex(
this.$route,
this.items
)
if (index > -1) {
this.openGroupIndex = index
}
},
toggleGroup (index) {
this.openGroupIndex = index === this.openGroupIndex ? -1 : index
},
isActive (page) {
return isActive(this.$route, page.regularPath)
}
}
}
function resolveOpenGroupIndex (route, items) {
for (let i = 0; i < items.length; i++) {
const item = items[i]
if (descendantIsActive(route, item)) {
return i
}
}
return -1
}
function descendantIsActive (route, item) {
if (item.type === 'group') {
return item.children.some(child => {
if (child.type === 'group') {
return descendantIsActive(route, child)
} else {
return child.type === 'page' && isActive(route, child.path)
}
})
}
return false
}
</script>
================================================
FILE: storage_redirect/.vuepress/theme/global-components/Badge.vue
================================================
<script>
export default {
functional: true,
props: {
type: {
type: String,
default: 'tip'
},
text: String,
vertical: {
type: String,
default: 'top'
}
},
render (h, { props, slots }) {
return h('span', {
class: ['badge', props.type],
style: {
verticalAlign: props.vertical
}
}, props.text || slots().default)
}
}
</script>
<style lang="stylus" scoped>
.badge
display inline-block
font-size 14px
height 18px
line-height 18px
border-radius 3px
padding 0 6px
color white
background-color #42b983
&.tip, &.green
background-color #42b983
&.error
background-color #DA5961 //#f66
&.warning, &.warn, &.yellow
background-color darken(#ffe564, 35%)
& + &
margin-left 5px
</style>
================================================
FILE: storage_redirect/.vuepress/theme/index.js
================================================
const path = require('path')
// Theme API.
module.exports = (options, ctx) => ({
alias() {
const { themeConfig, siteConfig } = ctx
// resolve algolia
const isAlgoliaSearch = (
themeConfig.algolia
|| Object.keys(siteConfig.locales && themeConfig.locales || {})
.some(base => themeConfig.locales[base].algolia)
)
return {
'@AlgoliaSearchBox': isAlgoliaSearch
? path.resolve(__dirname, 'components/AlgoliaSearchBox.vue')
: path.resolve(__dirname, 'noopModule.js')
}
},
plugins: [
['@vuepress/active-header-links', options.activeHeaderLinks],
'@vuepress/search',
'@vuepress/plugin-nprogress',
['container', {
type: 'tip',
defaultTitle: {
'/zh/': '提示'
}
}],
['container', {
type: 'warning',
defaultTitle: {
'/zh/': '注意'
}
}],
['container', {
type: 'danger',
defaultTitle: {
'/zh/': '警告'
}
}],
['container', {
type: 'details',
before: info => `<details class="custom-block details">${info ? `<summary>${info}</summary>` : ''}\n`,
after: () => '</details>\n'
}]
]
})
================================================
FILE: storage_redirect/.vuepress/theme/layouts/404.vue
================================================
<template>
<div class="theme-container">
<div class="theme-default-content">
<h1>404</h1>
<blockquote>{{ getMsg() }}</blockquote>
<router-link to="/">Take me home.</router-link>
</div>
</div>
</template>
<script>
const msgs = [
`There's nothing here.`,
`How did we get here?`,
`That's a Four-Oh-Four.`,
`Looks like we've got some broken links.`
]
export default {
methods: {
getMsg () {
return msgs[Math.floor(Math.random() * msgs.length)]
}
}
}
</script>
================================================
FILE: storage_redirect/.vuepress/theme/layouts/Layout.vue
================================================
<template>
<div
class="theme-container"
:class="pageClasses"
@touchstart="onTouchStart"
@touchend="onTouchEnd"
>
<Navbar
v-if="shouldShowNavbar"
@toggle-sidebar="toggleSidebar"
/>
<div
class="sidebar-mask"
@click="toggleSidebar(false)"
></div>
<Sidebar
:items="sidebarItems"
@toggle-sidebar="toggleSidebar"
>
<slot
name="sidebar-top"
slot="top"
/>
<slot
name="sidebar-bottom"
slot="bottom"
/>
</Sidebar>
<Home v-if="$page.frontmatter.home"/>
<Page
v-else
:sidebar-items="sidebarItems"
>
<slot
name="page-top"
slot="top"
/>
<slot
name="page-bottom"
slot="bottom"
/>
</Page>
</div>
</template>
<script>
import Home from '@theme/components/Home.vue'
import Download from '@theme/components/Download.vue'
import Navbar from '@theme/components/Navbar.vue'
import Page from '@theme/components/Page.vue'
import Sidebar from '@theme/components/Sidebar.vue'
import { resolveSidebarItems } from '../util'
export default {
components: { Home, Download, Page, Sidebar, Navbar },
data () {
return {
isSidebarOpen: false
}
},
computed: {
shouldShowNavbar () {
const { themeConfig } = this.$site
const { frontmatter } = this.$page
if (
frontmatter.navbar === false
|| themeConfig.navbar === false) {
return false
}
return (
this.$title
|| themeConfig.logo
|| themeConfig.repo
|| themeConfig.nav
|| this.$themeLocaleConfig.nav
)
},
shouldShowSidebar () {
const { frontmatter } = this.$page
return (
!frontmatter.home
&& !frontmatter.download
&& frontmatter.sidebar !== false
&& this.sidebarItems.length
)
},
sidebarItems () {
return resolveSidebarItems(
this.$page,
this.$page.regularPath,
this.$site,
this.$localePath
)
},
pageClasses () {
const userPageClass = this.$page.frontmatter.pageClass
return [
{
'no-navbar': !this.shouldShowNavbar,
'sidebar-open': this.isSidebarOpen,
'no-sidebar': !this.shouldShowSidebar
},
userPageClass
]
}
},
mounted () {
this.$router.afterEach(() => {
this.isSidebarOpen = false
})
},
methods: {
toggleSidebar (to) {
this.isSidebarOpen = typeof to === 'boolean' ? to : !this.isSidebarOpen
this.$emit('toggle-sidebar', this.isSidebarOpen)
},
// side swipe
onTouchStart (e) {
this.touchStart = {
x: e.changedTouches[0].clientX,
y: e.changedTouches[0].clientY
}
},
onTouchEnd (e) {
const dx = e.changedTouches[0].clientX - this.touchStart.x
const dy = e.changedTouches[0].clientY - this.touchStart.y
if (Math.abs(dx) > Math.abs(dy) && Math.abs(dx) > 40) {
if (dx > 0 && this.touchStart.x <= 80) {
this.toggleSidebar(true)
} else {
this.toggleSidebar(false)
}
}
}
}
}
</script>
================================================
FILE: storage_redirect/.vuepress/theme/noopModule.js
================================================
export default {}
================================================
FILE: storage_redirect/.vuepress/theme/styles/arrow.styl
================================================
@require './config'
.arrow
display inline-block
width 0
height 0
&.up
border-left 4px solid transparent
border-right 4px solid transparent
border-bottom 6px solid $arrowBgColor
&.down
border-left 4px solid transparent
border-right 4px solid transparent
border-top 6px solid $arrowBgColor
&.right
border-top 4px solid transparent
border-bottom 4px solid transparent
border-left 6px solid $arrowBgColor
&.left
border-top 4px solid transparent
border-bottom 4px solid transparent
border-right 6px solid $arrowBgColor
================================================
FILE: storage_redirect/.vuepress/theme/styles/code.styl
================================================
{$contentClass}
code
color lighten($textColor, 20%)
padding 0.25rem 0.5rem
margin 0
font-size 0.85em
background-color rgba(27,31,35,0.05)
border-radius 3px
.token
&.deleted
color #EC5975
&.inserted
color $accentColor
{$contentClass}
pre, pre[class*="language-"]
line-height 1.4
padding 1.25rem 1.5rem
margin 0.85rem 0
background-color $codeBgColor
border-radius 6px
overflow auto
code
color #fff
padding 0
background-color transparent
border-radius 0
div[class*="language-"]
position relative
background-color $codeBgColor
border-radius 6px
.highlight-lines
user-select none
padding-top 1.3rem
position absolute
top 0
left 0
width 100%
line-height 1.4
.highlighted
background-color rgba(0, 0, 0, 66%)
pre, pre[class*="language-"]
background transparent
position relative
z-index 1
&::before
position absolute
z-index 3
top 0.8em
right 1em
font-size 0.75rem
color rgba(255, 255, 255, 0.4)
&:not(.line-numbers-mode)
.line-numbers-wrapper
display none
&.line-numbers-mode
.highlight-lines .highlighted
position relative
&:before
content ' '
position absolute
z-index 3
left 0
top 0
display block
width $lineNumbersWrapperWidth
height 100%
background-color rgba(0, 0, 0, 66%)
pre
padding-left $lineNumbersWrapperWidth + 1 rem
vertical-align middle
.line-numbers-wrapper
position absolute
top 0
width $lineNumbersWrapperWidth
text-align center
color rgba(255, 255, 255, 0.3)
padding 1.25rem 0
line-height 1.4
br
user-select none
.line-number
position relative
z-index 4
user-select none
font-size 0.85em
&::after
content ''
position absolute
z-index 2
top 0
left 0
width $lineNumbersWrapperWidth
height 100%
border-radius 6px 0 0 6px
border-right 1px solid rgba(0, 0, 0, 66%)
background-color $codeBgColor
for lang in $codeLang
div{'[class~="language-' + lang + '"]'}
&:before
content ('' + lang)
div[class~="language-javascript"]
&:before
content "js"
div[class~="language-typescript"]
&:before
content "ts"
div[class~="language-markup"]
&:before
content "html"
div[class~="language-markdown"]
&:before
content "md"
div[class~="language-json"]:before
content "json"
div[class~="language-ruby"]:before
content "rb"
div[class~="language-python"]:before
content "py"
div[class~="language-bash"]:before
content "sh"
div[class~="language-php"]:before
content "php"
@import '~prismjs/themes/prism-tomorrow.css'
================================================
FILE: storage_redirect/.vuepress/theme/styles/config.styl
================================================
$contentClass = '.theme-default-content'
================================================
FILE: storage_redirect/.vuepress/theme/styles/custom-blocks.styl
================================================
.custom-block
.custom-block-title
font-weight 600
margin-bottom -0.4rem
&.tip, &.warning, &.danger
padding .1rem 1.5rem
border-left-width .5rem
border-left-style solid
margin 1rem 0
&.tip
background-color #f3f5f7
border-color #42b983
&.warning
background-color rgba(255,229,100,.3)
border-color darken(#ffe564, 35%)
color darken(#ffe564, 70%)
.custom-block-title
color darken(#ffe564, 50%)
a
color $textColor
&.danger
background-color #ffe6e6
border-color darken(red, 20%)
color darken(red, 70%)
.custom-block-title
color darken(red, 40%)
a
color $textColor
&.details
display block
position relative
border-radius 2px
margin 1.6em 0
padding 1.6em
background-color #eee
h4
margin-top 0
figure, p
&:last-child
margin-bottom 0
padding-bottom 0
summary
outline none
cursor pointer
================================================
FILE: storage_redirect/.vuepress/theme/styles/index.styl
================================================
@require './config'
@require './code'
@require './custom-blocks'
@require './arrow'
@require './wrapper'
@require './toc'
code
overflow: auto
word-wrap:break-word
body
font-family Roboto, sans-serif
body:lang(zh-hans)
font-family Roboto, 'Noto Sans SC', sans-serif
body:lang(zh-hant)
font-family Roboto, 'Noto Sans TC', sans-serif
em
font-style italic
font-variation-settings "ital" 1
html, body
padding 0
margin 0
background-color #fff
body
-webkit-font-smoothing antialiased
-moz-osx-font-smoothing grayscale
font-size 16px
color $textColor
.page
padding-left $sidebarWidth
.navbar
position fixed
z-index 20
top 0
left 0
right 0
height $navbarHeight
background-color #fff
box-sizing border-box
border-bottom 1px solid $borderColor
.sidebar-mask
position fixed
z-index 9
top 0
left 0
width 100vw
height 100vh
display none
.sidebar
font-size 16px
background-color #fff
width $sidebarWidth
position fixed
z-index 10
margin 0
top $navbarHeight
left 0
bottom 0
box-sizing border-box
border-right 1px solid $borderColor
overflow-y auto
{$contentClass}:not(.custom)
@extend $wrapper
> *:first-child
margin-top $navbarHeight
a:hover
text-decoration underline
p.demo
padding 1rem 1.5rem
border 1px solid #ddd
border-radius 4px
img
max-width 100%
{$contentClass}.custom
padding 0
margin 0
img
max-width 100%
a
font-weight 500
color $accentColor
text-decoration none
p a code
font-weight 400
color $accentColor
kbd
background #eee
border solid 0.15rem #ddd
border-bottom solid 0.25rem #ddd
border-radius 0.15rem
padding 0 0.15em
blockquote
font-size 1rem
color #999;
border-left .2rem solid #dfe2e5
margin 1rem 0
padding .25rem 0 .25rem 1rem
& > p
margin 0
ul, ol
padding-left 1.2em
strong
font-weight 600
h1, h2, h3, h4, h5, h6
font-weight 600
line-height 1.25
{$contentClass}:not(.custom) > &
margin-top (0.5rem - $navbarHeight)
padding-top ($navbarHeight + 1rem)
margin-bottom 0
&:first-child
margin-top -1.5rem
margin-bottom 1rem
+ p, + pre, + .custom-block
margin-top 2rem
&:hover .header-anchor
opacity: 1
h1
font-size 2.2rem
h2
font-size 1.65rem
padding-bottom .3rem
border-bottom 1px solid $borderColor
h3
font-size 1.35rem
a.header-anchor
font-size 0.85em
float left
margin-left -0.87em
padding-right 0.23em
margin-top 0.125em
opacity 0
&:hover
text-decoration none
code, kbd, .line-number
font-family 'Roboto Mono', 'Source Code Pro BDC', monospace
p, ul, ol
line-height 1.7
hr
border 0
border-top 1px solid $borderColor
table
border-collapse collapse
margin 1rem 0
display: block
overflow-x: auto
tr
border-top 1px solid #dfe2e5
&:nth-child(2n)
background-color #f6f8fa
th, td
border 1px solid #dfe2e5
padding .6em 1em
.theme-container
&.sidebar-open
.sidebar-mask
display: block
&.no-navbar
{$contentClass}:not(.custom) > h1, h2, h3, h4, h5, h6
margin-top 1.5rem
padding-top 0
.sidebar
top 0
@media (min-width: ($MQMobile + 1px))
.theme-container.no-sidebar
.sidebar
display none
.page
padding-left 0
@require 'mobile.styl'
================================================
FILE: storage_redirect/.vuepress/theme/styles/mobile.styl
================================================
@require './config'
$mobileSidebarWidth = $sidebarWidth * 0.82
// narrow desktop / iPad
@media (max-width: $MQNarrow)
.sidebar
font-size 15px
width $mobileSidebarWidth
.page
padding-left $mobileSidebarWidth
// wide mobile
@media (max-width: $MQMobile)
.sidebar
top 0
padding-top $navbarHeight
transform translateX(-100%)
transition transform .2s ease
.page
padding-left 0
.theme-container
&.sidebar-open
.sidebar
transform translateX(0)
&.no-navbar
.sidebar
padding-top: 0
// narrow mobile
@media (max-width: $MQMobileNarrow)
h1
font-size 1.9rem
{$contentClass}
div[class*="language-"]
margin 0.85rem -1.5rem
border-radius 0
================================================
FILE: storage_redirect/.vuepress/theme/styles/palette.styl
================================================
$accentColor = #01579B
$textColor = #2c3e50
$borderColor = #eaecef
$codeBgColor = #282c34
================================================
FILE: storage_redirect/.vuepress/theme/styles/toc.styl
================================================
.table-of-contents
.badge
vertical-align middle
================================================
FILE: storage_redirect/.vuepress/theme/styles/wrapper.styl
================================================
$wrapper
max-width $contentWidth
margin 0 auto
padding 2rem 2.5rem
@media (max-width: $MQNarrow)
padding 2rem
@media (max-width: $MQMobileNarrow)
padding 1.5rem
================================================
FILE: storage_redirect/.vuepress/theme/util/index.js
================================================
export const hashRE = /#.*$/
export const extRE = /\.(md|html)$/
export const endingSlashRE = /\/$/
export const outboundRE = /^[a-z]+:/i
export function normalize (path) {
return decodeURI(path)
.replace(hashRE, '')
.replace(extRE, '')
}
export function getHash (path) {
const match = path.match(hashRE)
if (match) {
return match[0]
}
}
export function isExternal (path) {
return outboundRE.test(path)
}
export function isMailto (path) {
return /^mailto:/.test(path)
}
export function isTel (path) {
return /^tel:/.test(path)
}
export function ensureExt (path) {
if (isExternal(path)) {
return path
}
const hashMatch = path.match(hashRE)
const hash = hashMatch ? hashMatch[0] : ''
const normalized = normalize(path)
if (endingSlashRE.test(normalized)) {
return path
}
return normalized + '.html' + hash
}
export function isActive (route, path) {
const routeHash = route.hash
const linkHash = getHash(path)
if (linkHash && routeHash !== linkHash) {
return false
}
const routePath = normalize(route.path)
const pagePath = normalize(path)
return routePath === pagePath
}
export function resolvePage (pages, rawPath, base) {
if (isExternal(rawPath)) {
return {
type: 'external',
path: rawPath
}
}
if (base) {
rawPath = resolvePath(rawPath, base)
}
const path = normalize(rawPath)
for (let i = 0; i < pages.length; i++) {
if (normalize(pages[i].regularPath) === path) {
return Object.assign({}, pages[i], {
type: 'page',
path: ensureExt(pages[i].path)
})
}
}
console.error(`[vuepress] No matching page found for sidebar item "${rawPath}"`)
return {}
}
function resolvePath (relative, base, append) {
const firstChar = relative.charAt(0)
if (firstChar === '/') {
return relative
}
if (firstChar === '?' || firstChar === '#') {
return base + relative
}
const stack = base.split('/')
// remove trailing segment if:
// - not appending
// - appending to trailing slash (last segment is empty)
if (!append || !stack[stack.length - 1]) {
stack.pop()
}
// resolve relative path
const segments = relative.replace(/^\//, '').split('/')
for (let i = 0; i < segments.length; i++) {
const segment = segments[i]
if (segment === '..') {
stack.pop()
} else if (segment !== '.') {
stack.push(segment)
}
}
// ensure leading slash
if (stack[0] !== '') {
stack.unshift('')
}
return stack.join('/')
}
/**
* @param { Page } page
* @param { string } regula
gitextract_c9c7yzyg/
├── .gitattributes
├── .github/
│ └── dependabot.yml
├── .gitignore
├── appops/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── components/
│ │ │ ├── Home.vue
│ │ │ └── SidebarLink.vue
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ └── Layout.vue
│ │ └── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ ├── guide/
│ │ ├── README.md
│ │ ├── faq/
│ │ │ ├── how_to_reset.md
│ │ │ └── purchase.md
│ │ ├── technical/
│ │ │ ├── run_in_background.md
│ │ │ └── system_behaviors.md
│ │ └── working_mode/
│ │ ├── dpm.md
│ │ └── shizuku.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── changelog.md
│ │ ├── download.md
│ │ └── guide/
│ │ ├── README.md
│ │ ├── faq/
│ │ │ ├── how_to_reset.md
│ │ │ └── purchase.md
│ │ ├── technical/
│ │ │ ├── run_in_background.md
│ │ │ └── system_behaviors.md
│ │ └── working_mode/
│ │ ├── dpm.md
│ │ └── shizuku.md
│ └── zh-hant/
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ └── guide/
│ ├── README.md
│ ├── faq/
│ │ ├── how_to_reset.md
│ │ └── purchase.md
│ ├── technical/
│ │ ├── run_in_background.md
│ │ └── system_behaviors.md
│ └── working_mode/
│ ├── dpm.md
│ └── shizuku.md
├── assets/
│ └── SourceCodePro-BDC.css
├── package.json
├── shizuku/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ └── Layout.vue
│ │ └── styles/
│ │ ├── index.styl
│ │ └── palette.styl
│ ├── README.md
│ ├── download.md
│ ├── guide/
│ │ └── setup.md
│ ├── introduction.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── download.md
│ │ ├── guide/
│ │ │ └── setup.md
│ │ └── introduction.md
│ └── zh-hant/
│ ├── README.md
│ ├── download.md
│ ├── guide/
│ │ └── setup.md
│ └── introduction.md
├── storage_redirect/
│ ├── .gitignore
│ ├── .vuepress/
│ │ ├── config.js
│ │ ├── public/
│ │ │ └── icon/
│ │ │ ├── browserconfig.xml
│ │ │ └── manifest.json
│ │ └── theme/
│ │ ├── LICENSE
│ │ ├── components/
│ │ │ ├── AlgoliaSearchBox.vue
│ │ │ ├── Download.vue
│ │ │ ├── DropdownLink.vue
│ │ │ ├── DropdownTransition.vue
│ │ │ ├── Home.vue
│ │ │ ├── NavLink.vue
│ │ │ ├── NavLinks.vue
│ │ │ ├── Navbar.vue
│ │ │ ├── Page.vue
│ │ │ ├── PageEdit.vue
│ │ │ ├── PageNav.vue
│ │ │ ├── Sidebar.vue
│ │ │ ├── SidebarButton.vue
│ │ │ ├── SidebarGroup.vue
│ │ │ ├── SidebarLink.vue
│ │ │ └── SidebarLinks.vue
│ │ ├── global-components/
│ │ │ └── Badge.vue
│ │ ├── index.js
│ │ ├── layouts/
│ │ │ ├── 404.vue
│ │ │ └── Layout.vue
│ │ ├── noopModule.js
│ │ ├── styles/
│ │ │ ├── arrow.styl
│ │ │ ├── code.styl
│ │ │ ├── config.styl
│ │ │ ├── custom-blocks.styl
│ │ │ ├── index.styl
│ │ │ ├── mobile.styl
│ │ │ ├── palette.styl
│ │ │ ├── toc.styl
│ │ │ └── wrapper.styl
│ │ └── util/
│ │ └── index.js
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ ├── guide/
│ │ ├── README.md
│ │ ├── advanced/
│ │ │ ├── shared_user_id.md
│ │ │ └── technical_details_export_isolated_files.md
│ │ ├── compatibility/
│ │ │ ├── README.md
│ │ │ ├── meizu.md
│ │ │ ├── miui.md
│ │ │ └── samsung.md
│ │ ├── contribute.md
│ │ ├── enhanced_mode/
│ │ │ ├── README.md
│ │ │ └── install.md
│ │ ├── faq/
│ │ │ ├── cant_find_app.md
│ │ │ ├── how_to_document.md
│ │ │ └── how_to_report_problems.md
│ │ └── tutorial.md
│ ├── zh-hans/
│ │ ├── README.md
│ │ ├── changelog.md
│ │ ├── download.md
│ │ └── guide/
│ │ ├── README.md
│ │ ├── advanced/
│ │ │ ├── shared_user_id.md
│ │ │ └── technical_details_export_isolated_files.md
│ │ ├── compatibility/
│ │ │ ├── README.md
│ │ │ ├── meizu.md
│ │ │ ├── miui.md
│ │ │ └── samsung.md
│ │ ├── contribute.md
│ │ ├── enhanced_mode/
│ │ │ ├── README.md
│ │ │ └── install.md
│ │ ├── faq/
│ │ │ ├── cant_find_app.md
│ │ │ ├── how_to_document.md
│ │ │ └── how_to_report_problems.md
│ │ └── tutorial.md
│ └── zh-hant/
│ ├── README.md
│ ├── changelog.md
│ ├── download.md
│ └── guide/
│ ├── README.md
│ ├── advanced/
│ │ ├── shared_user_id.md
│ │ └── technical_details_export_isolated_files.md
│ ├── compatibility/
│ │ ├── README.md
│ │ ├── meizu.md
│ │ ├── miui.md
│ │ └── samsung.md
│ ├── contribute.md
│ ├── enhanced_mode/
│ │ ├── README.md
│ │ └── install.md
│ ├── faq/
│ │ ├── cant_find_app.md
│ │ ├── how_to_document.md
│ │ └── how_to_report_problems.md
│ └── tutorial.md
├── webhooks/
│ ├── .gitignore
│ ├── index.js
│ └── package.json
└── www/
├── .gitignore
├── .vuepress/
│ ├── config.js
│ ├── public/
│ │ └── robots.txt
│ └── theme/
│ ├── components/
│ │ ├── Home.vue
│ │ └── SidebarLink.vue
│ ├── index.js
│ ├── layouts/
│ │ └── Layout.vue
│ └── styles/
│ ├── index.styl
│ └── palette.styl
├── README.md
├── contribute_translation.md
├── knowledge/
│ ├── exit_on_start.md
│ └── google_play_purchase.md
├── privacy_policy.md
├── zh-hans/
│ ├── README.md
│ ├── contribute_translation.md
│ └── knowledge/
│ ├── exit_on_start.md
│ └── google_play_purchase.md
└── zh-hant/
├── README.md
├── contribute_translation.md
└── knowledge/
├── exit_on_start.md
└── google_play_purchase.md
SYMBOL INDEX (29 symbols across 7 files)
FILE: appops/.vuepress/config.js
function getSidebar (line 157) | function getSidebar(prefix, basicTitle, workingModeTitle, faqTitle, tech...
function getNavbar (line 199) | function getNavbar(prefix, guide, download, changelog, allRikkaApps) {
FILE: shizuku/.vuepress/config.js
function getNavbar (line 156) | function getNavbar(prefix, introduction, guide, download, dev) {
FILE: storage_redirect/.vuepress/config.js
function getSidebar (line 165) | function getSidebar(prefix, basicTitle, advancedTitle, enhancedModeTitle...
function getNavbar (line 220) | function getNavbar(prefix, guide, download, changelog, allRikkaApps) {
FILE: storage_redirect/.vuepress/theme/index.js
method alias (line 5) | alias() {
FILE: storage_redirect/.vuepress/theme/util/index.js
function normalize (line 6) | function normalize (path) {
function getHash (line 12) | function getHash (path) {
function isExternal (line 19) | function isExternal (path) {
function isMailto (line 23) | function isMailto (path) {
function isTel (line 27) | function isTel (path) {
function ensureExt (line 31) | function ensureExt (path) {
function isActive (line 45) | function isActive (route, path) {
function resolvePage (line 56) | function resolvePage (pages, rawPath, base) {
function resolvePath (line 79) | function resolvePath (relative, base, append) {
function resolveSidebarItems (line 124) | function resolveSidebarItems (page, regularPath, site, localePath) {
function resolveHeaders (line 151) | function resolveHeaders (page) {
function groupHeaders (line 168) | function groupHeaders (headers) {
function resolveNavLinkItem (line 182) | function resolveNavLinkItem (linkItem) {
function resolveMatchingConfig (line 193) | function resolveMatchingConfig (regularPath, config) {
function ensureEndingSlash (line 211) | function ensureEndingSlash (path) {
function resolveItem (line 217) | function resolveItem (item, pages, base, groupDepth = 1) {
FILE: webhooks/index.js
function buildVuePress (line 20) | async function buildVuePress(path) {
function purgeCloudflareCache (line 28) | async function purgeCloudflareCache(urls) {
function collectTargets (line 52) | function collectTargets(body) {
function collectFiles (line 70) | function collectFiles(parent, files) {
function collectUrls (line 81) | function collectUrls(target, path) {
FILE: www/.vuepress/config.js
function getSidebar (line 152) | function getSidebar(prefix, knowledgeTitle) {
function getNavbar (line 167) | function getNavbar(prefix, knowledge, translation) {
Condensed preview — 177 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (498K chars).
[
{
"path": ".gitattributes",
"chars": 104,
"preview": "* 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",
"chars": 284,
"preview": "version: 2\nupdates:\n\n # Maintain dependencies for GitHub Actions\n - package-ecosystem: \"github-actions\"\n directory:"
},
{
"path": ".gitignore",
"chars": 34,
"preview": "/.vscode\n/node_modules\n/yarn.lock\n"
},
{
"path": "appops/.gitignore",
"chars": 15,
"preview": "/.vuepress/dist"
},
{
"path": "appops/.vuepress/config.js",
"chars": 5815,
"preview": "const moment = require('moment')\nconst langMap = {\n \"zh-Hans\": \"zh-cn\",\n \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}"
},
{
"path": "appops/.vuepress/public/icon/browserconfig.xml",
"chars": 281,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><s"
},
{
"path": "appops/.vuepress/public/icon/manifest.json",
"chars": 720,
"preview": "{\n \"name\": \"App\",\n \"icons\": [\n {\n \"src\": \"\\/android-icon-36x36.png\",\n \"sizes\": \"36x36\",\n \"type\": \"image\\/png\",\n "
},
{
"path": "appops/.vuepress/theme/components/Home.vue",
"chars": 4262,
"preview": "<template>\n <main class=\"home\" aria-labelledby=\"main-title\">\n <header class=\"hero\">\n <img\n v-if=\"data.he"
},
{
"path": "appops/.vuepress/theme/components/SidebarLink.vue",
"chars": 3163,
"preview": "<script>\nimport { isActive, hashRE, groupHeaders } from '@parent-theme/util'\n\nexport default {\n functional: true,\n\n pr"
},
{
"path": "appops/.vuepress/theme/index.js",
"chars": 56,
"preview": "module.exports = {\n extend: '@vuepress/theme-default'\n}"
},
{
"path": "appops/.vuepress/theme/layouts/Layout.vue",
"chars": 176,
"preview": "<template>\n <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport de"
},
{
"path": "appops/.vuepress/theme/styles/index.styl",
"chars": 222,
"preview": "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 Ro"
},
{
"path": "appops/.vuepress/theme/styles/palette.styl",
"chars": 89,
"preview": "$accentColor = #1565c0\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
},
{
"path": "appops/README.md",
"chars": 931,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: Download\nactionLink: /download.html\nsecondaryActionText: Learn more\nseco"
},
{
"path": "appops/changelog.md",
"chars": 19961,
"preview": "# 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 wo"
},
{
"path": "appops/download.md",
"chars": 220,
"preview": "# Download\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com"
},
{
"path": "appops/guide/README.md",
"chars": 2518,
"preview": "# Learn App Ops\n\nIn short, **App Ops** is an app that **modifies the settings of \"appops\" in Android system**.\n\n## What "
},
{
"path": "appops/guide/faq/how_to_reset.md",
"chars": 178,
"preview": "# 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-se"
},
{
"path": "appops/guide/faq/purchase.md",
"chars": 193,
"preview": "# Purchase or restore problems\n\n## Google Play restore\n\nIn most cases, follow the prompts that appear after clicking the"
},
{
"path": "appops/guide/technical/run_in_background.md",
"chars": 1716,
"preview": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND` (Run in background)\n\n\"Run in background\" seen in the App Ops app actually "
},
{
"path": "appops/guide/technical/system_behaviors.md",
"chars": 5605,
"preview": "# Difference under different Android versions\n\nEach op has two modes, `package mode` and `uid mode`. `uid mode` has high"
},
{
"path": "appops/guide/working_mode/dpm.md",
"chars": 3973,
"preview": "# Delegated Device Admin mode\n\n::: warning Warning\n\nAs of 6.0.0, this working mode is no longer supported. To continue u"
},
{
"path": "appops/guide/working_mode/shizuku.md",
"chars": 779,
"preview": "# Shizuku mode\n\n## Requirements and Features\n\n* Need to install Shizuku app and start Shizuku service via adb or root\n* "
},
{
"path": "appops/zh-hans/README.md",
"chars": 549,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 立即下载\nactionLink: /zh-hans/download.html\nsecondaryActionText: 了解更多\nsecond"
},
{
"path": "appops/zh-hans/changelog.md",
"chars": 10657,
"preview": "# 变更日志\n\n## 9.0.6 (2023-08-03)\n\n- 升级 Shizuku 到 13.5.0 以上可能可以解决自动化功能不工作的问题\n- 修复在部分 realme 设备上“无法启动服务”的问题\n- 修复在 Android 7.1"
},
{
"path": "appops/zh-hans/download.md",
"chars": 215,
"preview": "# 下载\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com/apk/r"
},
{
"path": "appops/zh-hans/guide/README.md",
"chars": 1094,
"preview": "# 了解 App Ops\n\n简而言之,**App Ops** 是一个修改 **Android 系统中的 \"appops\" 设置** 的应用。\n\n## 什么是 Android 系统中的 \"appops\"\n\n在 Android 系统中存在一个叫"
},
{
"path": "appops/zh-hans/guide/faq/how_to_reset.md",
"chars": 74,
"preview": "### 如何重置全部设置?\n\n1. 切换到应用列表模式\n2. 长按或点击左侧应用图标进入多选模式\n3. 右上方三点菜单 - 全选\n4. 选择“重置”"
},
{
"path": "appops/zh-hans/guide/faq/purchase.md",
"chars": 77,
"preview": "# 购买或恢复问题\n\n## Google Play 恢复问题\n\n大部分情况下,按照点击购买后出现的提示文字处理即可,如果仍不能解决问题,请发送邮件给我们。"
},
{
"path": "appops/zh-hans/guide/technical/run_in_background.md",
"chars": 1072,
"preview": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`(在后台运行)\n\n在 App Ops 应用中看到的“在后台运行”实际是指 `RUN_IN_BACKGROUND`(Android 7 起增加)和 `R"
},
{
"path": "appops/zh-hans/guide/technical/system_behaviors.md",
"chars": 3515,
"preview": "# 不同 Android 版本下的不同\n\n每个 op 都有两种 mode,分别为 `package mode` 和 `uid mode`。`uid mode` **有更高优先级**,即只有当 `uid mode` 为默认值时才会使用 `pa"
},
{
"path": "appops/zh-hans/guide/working_mode/dpm.md",
"chars": 2577,
"preview": "# 托管设备管理员模式\n\n::: warning 警告\n\n从 6.0.0 起,此工作模式不再支持。若要继续使用此工作模式,请[下载 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-t"
},
{
"path": "appops/zh-hans/guide/working_mode/shizuku.md",
"chars": 419,
"preview": "# Shizuku 模式\n\n## 需求及特性\n\n* 需要安装 Shizuku 应用并通过 adb 或 root 启动 Shizuku 服务\n* 支持多用户\n\n::: tip\n如果使用 adb,每次开机都需要使用 adb 进行启动 Shizu"
},
{
"path": "appops/zh-hant/README.md",
"chars": 551,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 立即下載\nactionLink: /zh-hant/download.html\nsecondaryActionText: 瞭解更多\nsecond"
},
{
"path": "appops/zh-hant/changelog.md",
"chars": 10655,
"preview": "# 變更日誌\n\n## 9.0.6 (2023-08-03)\n\n- 升級 Shizuku 到 13.5.0 以上可能可以解決自動化功能不工作的問題\n- 修復在部分 realme 裝置上「無法啟動服務」的問題\n- 修復在 Android 7.1"
},
{
"path": "appops/zh-hant/download.md",
"chars": 213,
"preview": "# 下載\n\n[Google Play](https://play.google.com/store/apps/details?id=rikka.appops)\n\n[Coolapk](https://www.coolapk.com/apk/r"
},
{
"path": "appops/zh-hant/guide/README.md",
"chars": 1097,
"preview": "# 瞭解 App Ops\n\n簡而言之,**App Ops** 是一個修改 **Android 系統中的 \"appops\" 設定** 的程式。\n\n## 什麼是 Android 系統中的 \"appops\"\n\n在 Android 系統中存在一個叫"
},
{
"path": "appops/zh-hant/guide/faq/how_to_reset.md",
"chars": 72,
"preview": "# 如何重置全部設定?\n\n1. 切換到應用列表模式\n2. 長按或點選左側應用圖示進入多選模式\n3. 右上方三點選單 - 全選\n4. 選擇「重置」"
},
{
"path": "appops/zh-hant/guide/faq/purchase.md",
"chars": 77,
"preview": "# 購買或恢復問題\n\n## Google Play 恢復問題\n\n大部分情況下,按照點擊購買後出現的提示文字處理即可,如果仍不能解決問題,請發送郵件給我們。"
},
{
"path": "appops/zh-hant/guide/technical/run_in_background.md",
"chars": 1072,
"preview": "# `RUN_IN_BACKGROUND`/`RUN_ANY_IN_BACKGROUND`(在後臺執行)\n\n在 App Ops 應用中看到的「在後臺執行」實際是指 `RUN_IN_BACKGROUND`(Android 7 起增加)和 `R"
},
{
"path": "appops/zh-hant/guide/technical/system_behaviors.md",
"chars": 3527,
"preview": "# 不同 Android 版本下的不同\n\n每個 op 都有兩種 mode,分別為 `package mode` 和 `uid mode`。`uid mode` **有更高優先順序**,即只有當 `uid mode` 為預設值時才會使用 `p"
},
{
"path": "appops/zh-hant/guide/working_mode/dpm.md",
"chars": 2603,
"preview": "# 託管裝置管理員模式\n\n::: warning 警告\n\n從 6.0.0 起,此工作模式不再支援。若要繼續使用此工作模式,請[下載 5.5.6 版本](https://github.com/RikkaApps/App-Ops-issue-t"
},
{
"path": "appops/zh-hant/guide/working_mode/shizuku.md",
"chars": 431,
"preview": "# Shizuku 模式\n\n## 需求及特性\n\n* 需要安裝 Shizuku 應用程式並通過 adb 或 root 啟動 Shizuku 服務\n* 支援多使用者\n\n::: tip\n如果使用 adb,每次開機都需要使用 adb 進行啟動 Sh"
},
{
"path": "assets/SourceCodePro-BDC.css",
"chars": 289,
"preview": "@font-face {\n font-family: 'Source Code Pro BDC';\n src: local('Source Code Pro'), local('SourceCodePro-Regular.ttf"
},
{
"path": "package.json",
"chars": 530,
"preview": "{\n \"dependencies\": {\n \"moment\": \"^2.29.1\",\n \"vuepress\": \"^1.8.2\",\n \"vuepress-plugin-clean-urls\": \"^1.1.2\",\n "
},
{
"path": "shizuku/.gitignore",
"chars": 15,
"preview": "/.vuepress/dist"
},
{
"path": "shizuku/.vuepress/config.js",
"chars": 4862,
"preview": "const moment = require('moment')\nconst langMap = {\n \"zh-Hans\": \"zh-cn\",\n \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}"
},
{
"path": "shizuku/.vuepress/public/icon/browserconfig.xml",
"chars": 281,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><s"
},
{
"path": "shizuku/.vuepress/public/icon/manifest.json",
"chars": 720,
"preview": "{\n \"name\": \"App\",\n \"icons\": [\n {\n \"src\": \"\\/android-icon-36x36.png\",\n \"sizes\": \"36x36\",\n \"type\": \"image\\/png\",\n "
},
{
"path": "shizuku/.vuepress/theme/index.js",
"chars": 56,
"preview": "module.exports = {\n extend: '@vuepress/theme-default'\n}"
},
{
"path": "shizuku/.vuepress/theme/layouts/Layout.vue",
"chars": 176,
"preview": "<template>\n <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport de"
},
{
"path": "shizuku/.vuepress/theme/styles/index.styl",
"chars": 222,
"preview": "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 Ro"
},
{
"path": "shizuku/.vuepress/theme/styles/palette.styl",
"chars": 89,
"preview": "$accentColor = #3949ab\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
},
{
"path": "shizuku/README.md",
"chars": 1211,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: Learn more\nactionLink: /introduction.html\nfeatures:\n- title: Use system "
},
{
"path": "shizuku/download.md",
"chars": 268,
"preview": "# Download\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](ht"
},
{
"path": "shizuku/guide/setup.md",
"chars": 6674,
"preview": "# User manual\n\n[[toc]]\n\n## Start Shizuku\n\nShizuku supports startup in the following three ways.\n\n::: tip If you are usin"
},
{
"path": "shizuku/introduction.md",
"chars": 2152,
"preview": "# Introduction\n\nShizuku can help normal apps uses system APIs directly with adb/root privileges with a Java process star"
},
{
"path": "shizuku/zh-hans/README.md",
"chars": 920,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 了解更多\nactionLink: /zh-hans/introduction.html\nfeatures:\n- title: 优雅地使用系统 A"
},
{
"path": "shizuku/zh-hans/download.md",
"chars": 328,
"preview": "# 下载\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](https://"
},
{
"path": "shizuku/zh-hans/guide/setup.md",
"chars": 3676,
"preview": "# 用户手册\n\n[[toc]]\n\n## 启动 Shizuku\n\nShizuku 支持通过以下三种方式启动。\n\n::: tip 如果您正在使用 GrapheneOS\n\n您可能需要关闭 系统设置 - “安全” - “Secure app spa"
},
{
"path": "shizuku/zh-hans/introduction.md",
"chars": 1084,
"preview": "# 简介\n\nShizuku 可以帮助普通应用借助一个由 app_process 启动的 Java 进程直接以 adb 或 root 特权使用系统 API。\n\n> Shizuku 这个名字来自[这里](https://www.pixiv.ne"
},
{
"path": "shizuku/zh-hant/README.md",
"chars": 922,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 瞭解更多\nactionLink: /zh-hant/introduction.html\nfeatures:\n- title: 優雅地使用系統 A"
},
{
"path": "shizuku/zh-hant/download.md",
"chars": 328,
"preview": "# 下載\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.privileged.api)\n\n[GitHub Release](https://"
},
{
"path": "shizuku/zh-hant/guide/setup.md",
"chars": 3732,
"preview": "# 使用者手冊\n\n[[toc]]\n\n## 啟動 Shizuku\n\nShizuku 支援透過以下三種方式啟動。\n\n::: tip 如果您正在使用 GrapheneOS\n\n您可能需要關閉 系統設定 - 「安全」 - 「Secure app sp"
},
{
"path": "shizuku/zh-hant/introduction.md",
"chars": 1087,
"preview": "# 簡介\n\nShizuku 可以幫助普通程式藉助一個由 app_process 啟動的 Java 程序直接以 adb 或 root 特權使用系統 API。\n\nShizuku 這個名字來自[這裡](https://www.pixiv.net/"
},
{
"path": "storage_redirect/.gitignore",
"chars": 15,
"preview": "/.vuepress/dist"
},
{
"path": "storage_redirect/.vuepress/config.js",
"chars": 6568,
"preview": "const moment = require('moment')\nconst langMap = {\n \"zh-Hans\": \"zh-cn\",\n \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}"
},
{
"path": "storage_redirect/.vuepress/public/icon/browserconfig.xml",
"chars": 281,
"preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<browserconfig><msapplication><tile><square70x70logo src=\"/ms-icon-70x70.png\"/><s"
},
{
"path": "storage_redirect/.vuepress/public/icon/manifest.json",
"chars": 720,
"preview": "{\n \"name\": \"App\",\n \"icons\": [\n {\n \"src\": \"\\/android-icon-36x36.png\",\n \"sizes\": \"36x36\",\n \"type\": \"image\\/png\",\n "
},
{
"path": "storage_redirect/.vuepress/theme/LICENSE",
"chars": 1091,
"preview": "The MIT License (MIT)\n\nCopyright (c) 2018-present, Yuxi (Evan) You\n\nPermission is hereby granted, free of charge, to any"
},
{
"path": "storage_redirect/.vuepress/theme/components/AlgoliaSearchBox.vue",
"chars": 4488,
"preview": "<template>\n <form\n id=\"search-form\"\n class=\"algolia-search-wrapper search-box\"\n role=\"search\"\n >\n <input\n "
},
{
"path": "storage_redirect/.vuepress/theme/components/Download.vue",
"chars": 172,
"preview": "<template>\n <main class=\"download\">\n </main>\n</template>\n\n<script>\nexport default {\n computed: {\n data() {\n r"
},
{
"path": "storage_redirect/.vuepress/theme/components/DropdownLink.vue",
"chars": 3994,
"preview": "<template>\n <div\n class=\"dropdown-wrapper\"\n :class=\"{ open }\"\n >\n <a\n class=\"dropdown-title\"\n @clic"
},
{
"path": "storage_redirect/.vuepress/theme/components/DropdownTransition.vue",
"chars": 560,
"preview": "<template>\n <transition\n name=\"dropdown\"\n @enter=\"setHeight\"\n @after-enter=\"unsetHeight\"\n @before-leave=\"se"
},
{
"path": "storage_redirect/.vuepress/theme/components/Home.vue",
"chars": 4251,
"preview": "<template>\n <main class=\"home\" aria-labelledby=\"main-title\">\n <header class=\"hero\">\n <img\n v-if=\"data.he"
},
{
"path": "storage_redirect/.vuepress/theme/components/NavLink.vue",
"chars": 882,
"preview": "<template>\n <router-link\n class=\"nav-link\"\n :to=\"link\"\n v-if=\"!isExternal(link)\"\n :exact=\"exact\"\n >{{ item"
},
{
"path": "storage_redirect/.vuepress/theme/components/NavLinks.vue",
"chars": 3677,
"preview": "<template>\n <nav\n class=\"nav-links\"\n v-if=\"userLinks.length || repoLink\"\n >\n <!-- user links -->\n <div\n "
},
{
"path": "storage_redirect/.vuepress/theme/components/Navbar.vue",
"chars": 3436,
"preview": "<template>\n <header class=\"navbar\">\n <SidebarButton @toggle-sidebar=\"$emit('toggle-sidebar')\"/>\n\n <router-link\n "
},
{
"path": "storage_redirect/.vuepress/theme/components/Page.vue",
"chars": 543,
"preview": "<template>\n <main class=\"page\">\n <slot name=\"top\" />\n\n <Content class=\"theme-default-content\" />\n <PageEdit />"
},
{
"path": "storage_redirect/.vuepress/theme/components/PageEdit.vue",
"chars": 3094,
"preview": "<template>\n <footer class=\"page-edit\">\n <div class=\"edit-link\" v-if=\"editLink\">\n <a :href=\"editLink\" target=\"_b"
},
{
"path": "storage_redirect/.vuepress/theme/components/PageNav.vue",
"chars": 2755,
"preview": "<template>\n <div class=\"page-nav\" v-if=\"prev || next\">\n <p class=\"inner\">\n <span v-if=\"prev\" class=\"prev\">\n "
},
{
"path": "storage_redirect/.vuepress/theme/components/Sidebar.vue",
"chars": 1218,
"preview": "<template>\n <aside class=\"sidebar\">\n <NavLinks/>\n <slot name=\"top\"/>\n <SidebarLinks :depth=\"0\" :items=\"items\"/"
},
{
"path": "storage_redirect/.vuepress/theme/components/SidebarButton.vue",
"chars": 919,
"preview": "<template>\n <div class=\"sidebar-button\" @click=\"$emit('toggle-sidebar')\">\n <svg class=\"icon\" xmlns=\"http://www.w3.or"
},
{
"path": "storage_redirect/.vuepress/theme/components/SidebarGroup.vue",
"chars": 2859,
"preview": "<template>\n <section\n class=\"sidebar-group\"\n :class=\"[\n {\n collapsable,\n 'is-sub-group': depth"
},
{
"path": "storage_redirect/.vuepress/theme/components/SidebarLink.vue",
"chars": 3156,
"preview": "<script>\nimport { isActive, hashRE, groupHeaders } from '@theme/util'\n\nexport default {\n functional: true,\n\n props: ['"
},
{
"path": "storage_redirect/.vuepress/theme/components/SidebarLinks.vue",
"chars": 1973,
"preview": "<template>\n <ul\n class=\"sidebar-links\"\n v-if=\"items.length\"\n >\n <li v-for=\"(item, i) in items\" :key=\"i\">\n "
},
{
"path": "storage_redirect/.vuepress/theme/global-components/Badge.vue",
"chars": 798,
"preview": "<script>\nexport default {\n functional: true,\n props: {\n type: {\n type: String,\n default: 'tip'\n },\n "
},
{
"path": "storage_redirect/.vuepress/theme/index.js",
"chars": 1176,
"preview": "const path = require('path')\n\n// Theme API.\nmodule.exports = (options, ctx) => ({\n alias() {\n const { themeConfig, s"
},
{
"path": "storage_redirect/.vuepress/theme/layouts/404.vue",
"chars": 514,
"preview": "<template>\n <div class=\"theme-container\">\n <div class=\"theme-default-content\">\n <h1>404</h1>\n <blockquote>"
},
{
"path": "storage_redirect/.vuepress/theme/layouts/Layout.vue",
"chars": 3213,
"preview": "<template>\n <div\n class=\"theme-container\"\n :class=\"pageClasses\"\n @touchstart=\"onTouchStart\"\n @touchend=\"onT"
},
{
"path": "storage_redirect/.vuepress/theme/noopModule.js",
"chars": 18,
"preview": "export default {}\n"
},
{
"path": "storage_redirect/.vuepress/theme/styles/arrow.styl",
"chars": 577,
"preview": "@require './config'\n\n.arrow\n display inline-block\n width 0\n height 0\n &.up\n border-left 4px solid transparent\n "
},
{
"path": "storage_redirect/.vuepress/theme/styles/code.styl",
"chars": 2861,
"preview": "{$contentClass}\n code\n color lighten($textColor, 20%)\n padding 0.25rem 0.5rem\n margin 0\n font-size 0.85em\n "
},
{
"path": "storage_redirect/.vuepress/theme/styles/config.styl",
"chars": 41,
"preview": "$contentClass = '.theme-default-content'\n"
},
{
"path": "storage_redirect/.vuepress/theme/styles/custom-blocks.styl",
"chars": 963,
"preview": ".custom-block\n .custom-block-title\n font-weight 600\n margin-bottom -0.4rem\n &.tip, &.warning, &.danger\n paddi"
},
{
"path": "storage_redirect/.vuepress/theme/styles/index.styl",
"chars": 3317,
"preview": "@require './config'\n@require './code'\n@require './custom-blocks'\n@require './arrow'\n@require './wrapper'\n@require './toc"
},
{
"path": "storage_redirect/.vuepress/theme/styles/mobile.styl",
"chars": 731,
"preview": "@require './config'\n\n$mobileSidebarWidth = $sidebarWidth * 0.82\n\n// narrow desktop / iPad\n@media (max-width: $MQNarrow)\n"
},
{
"path": "storage_redirect/.vuepress/theme/styles/palette.styl",
"chars": 89,
"preview": "$accentColor = #01579B\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
},
{
"path": "storage_redirect/.vuepress/theme/styles/toc.styl",
"chars": 54,
"preview": ".table-of-contents\n .badge\n vertical-align middle\n"
},
{
"path": "storage_redirect/.vuepress/theme/styles/wrapper.styl",
"chars": 180,
"preview": "$wrapper\n max-width $contentWidth\n margin 0 auto\n padding 2rem 2.5rem\n @media (max-width: $MQNarrow)\n padding 2re"
},
{
"path": "storage_redirect/.vuepress/theme/util/index.js",
"chars": 5803,
"preview": "export const hashRE = /#.*$/\nexport const extRE = /\\.(md|html)$/\nexport const endingSlashRE = /\\/$/\nexport const outboun"
},
{
"path": "storage_redirect/README.md",
"chars": 602,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: Download\nactionLink: /download.html\nsecondaryActionText: Learn more\nseco"
},
{
"path": "storage_redirect/changelog.md",
"chars": 36692,
"preview": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- Fixed an issue that on Android 10+, \"Export isolated files & Redirect system provi"
},
{
"path": "storage_redirect/download.md",
"chars": 554,
"preview": "# Download\n\n**Requirement:** rooted Android 6.0+ device\n\n[Google Play](https://play.google.com/store/apps/details?id=moe"
},
{
"path": "storage_redirect/guide/README.md",
"chars": 5498,
"preview": "# Introduction\n\nAs of the time of this writing (2023-03-06), the abuse of public storage by applications in Android is s"
},
{
"path": "storage_redirect/guide/advanced/shared_user_id.md",
"chars": 1962,
"preview": "# App group\n\nThe Shared User ID mechanism of the Android system allows multiple apps to share the same Linux user ID and"
},
{
"path": "storage_redirect/guide/advanced/technical_details_export_isolated_files.md",
"chars": 1538,
"preview": "# Technical details (Export isolated files)\n\nSuppose an app `com.example` saves images to `images` folder. Created a rul"
},
{
"path": "storage_redirect/guide/compatibility/README.md",
"chars": 396,
"preview": "# Overview\n\n* [Samsung](./samsung.md)\n* [Meizu](./meizu.md)\n* [Xiaomi (MIUI)](./miui.md)\n* Other problems\n\n * log is di"
},
{
"path": "storage_redirect/guide/compatibility/meizu.md",
"chars": 214,
"preview": "# 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 \""
},
{
"path": "storage_redirect/guide/compatibility/miui.md",
"chars": 1733,
"preview": "# Xiaomi (MIUI)\n\nMIUI has a series of restrictions which **enabled by default**. However, these restrictions are too rid"
},
{
"path": "storage_redirect/guide/compatibility/samsung.md",
"chars": 254,
"preview": "# Samsung\n\nFor unknown reasons, on some Samsung devices, execute a 64-bit executable in root user will always get a `Per"
},
{
"path": "storage_redirect/guide/contribute.md",
"chars": 338,
"preview": "# Contribute online rules\n\nCurrently, you need to manually create issues on GitHub. Please follow the steps below.\n\n1. C"
},
{
"path": "storage_redirect/guide/enhanced_mode/README.md",
"chars": 882,
"preview": "# Why Enhanced mode is necessary?\n\n-----------------------\n\nEnhanced mode provides the following features:\n\n1. No longer"
},
{
"path": "storage_redirect/guide/enhanced_mode/install.md",
"chars": 2143,
"preview": "# Install\n\nThe boost module requires your device to have Magisk installed first. You can learn more about Magisk from [G"
},
{
"path": "storage_redirect/guide/faq/cant_find_app.md",
"chars": 644,
"preview": "# Can't find some apps\n\nOnly apps which request read <b>and</b> write storage permission will be shown (i.e., apps reque"
},
{
"path": "storage_redirect/guide/faq/how_to_document.md",
"chars": 1531,
"preview": "# How to use the Document (Files) app\n\nThe Document app is part of the Android system. The advantage is that users can u"
},
{
"path": "storage_redirect/guide/faq/how_to_report_problems.md",
"chars": 1208,
"preview": "# Report problems\n\nThis document will teach you how to report problems.\n\n> For problems that are limited to a specific a"
},
{
"path": "storage_redirect/guide/tutorial.md",
"chars": 11729,
"preview": "# Tutorial\n\n## What happens when isolation is enabled?\n\nAssuming there is an application called ExampleApp (the package "
},
{
"path": "storage_redirect/zh-hans/README.md",
"chars": 373,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 下载\nactionLink: /zh-hans/download.html\nsecondaryActionText: 了解更多\nsecondar"
},
{
"path": "storage_redirect/zh-hans/changelog.md",
"chars": 24042,
"preview": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- 修复了在 Android 10 以上,没有写存储权限的应用没有显示“导出被隔离的文件 & 重定向系统提供程序”选项的问题\n \n 在 Android 10 以上,"
},
{
"path": "storage_redirect/zh-hans/download.md",
"chars": 379,
"preview": "# 下载\n\n**需求:** 已 root 的 Android 6.0 以上设备\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.redirec"
},
{
"path": "storage_redirect/zh-hans/guide/README.md",
"chars": 2324,
"preview": "# 介绍\n\n截至本文编写的时间(2023-03-06),在 Android 系统中应用对公共存储空间的滥用仍然是一个没有解决的问题。\n\n存储空间隔离致力于在尽可能小或不影响应用功能的前提下,解决这一问题。\n\n要清楚地说明这个问题,我们不得不"
},
{
"path": "storage_redirect/zh-hans/guide/advanced/shared_user_id.md",
"chars": 878,
"preview": "# 程序组\n\nAndroid 系统的 Shared User ID 机制允许多个应用享有相同的 Linux user ID 及 Android 权限,相互访问文件甚至运行在同一个进程。这些应用需要有具有相同签名。Shared User ID"
},
{
"path": "storage_redirect/zh-hans/guide/advanced/technical_details_export_isolated_files.md",
"chars": 892,
"preview": "# 技术细节(导出被隔离的文件)\n\n假设有一个应用 `com.example` 保存图片至 `images` 文件夹。建立了一条来源文件夹 `images`,目标文件夹 `Pictures/Example` 的规则。\n\n```\n/stora"
},
{
"path": "storage_redirect/zh-hans/guide/compatibility/README.md",
"chars": 228,
"preview": "# 概览\n\n* [三星](./samsung.md)\n* [魅族](./meizu.md)\n* [小米(MIUI)](./miui.md)\n* 其他\n\n * log 被关闭问题\n\n 在“开发者设置”中检查 log 是否开启。另外,据"
},
{
"path": "storage_redirect/zh-hans/guide/compatibility/meizu.md",
"chars": 110,
"preview": "# 魅族\n\n如果你可以使用 Magisk,你不会遇到问题。\n\n如果你不能使用 Magisk,不要为系统的“设置”应用(或其所属的[程序组](./../advanced/shared_user_id.html))启用隔离。"
},
{
"path": "storage_redirect/zh-hans/guide/compatibility/miui.md",
"chars": 630,
"preview": "# 小米(MIUI)\n\nMIUI 有一系列**默认启用**的限制。然而这些限制过于离谱,应用正常的功能经常因此被破坏。\n\n更令人生气的是,这些限制由 MIUI 的在线规则控制,并且对于微信这样在中国大陆地区流行的应用不会开启。\n\n## “在"
},
{
"path": "storage_redirect/zh-hans/guide/compatibility/samsung.md",
"chars": 129,
"preview": "# 三星\n\n由于未知原因,在部分三星设备上,以 root 用户中执行 64 位可执行程序,其中 `exec` 函数必定会 `Permission denied`。\n\n解决方法很简单,卸载后安装 [arm 版本](./../../downlo"
},
{
"path": "storage_redirect/zh-hans/guide/contribute.md",
"chars": 224,
"preview": "# 贡献在线规则\n\n目前需要人工在 GitHub 建立 issue。请按照下面的步骤进行。\n\n1. 如果你没有 [GitHub](https://github.com/) 账号,创建一个\n2. [建立新的 issue](https://gi"
},
{
"path": "storage_redirect/zh-hans/guide/enhanced_mode/README.md",
"chars": 345,
"preview": "# 为何增强模式是必要的?\n\n-----------------------\n\n增强模式提供以下功能:\n\n1. 不再需要依赖 `logcat` 侦测 app 进程创建\n - 规避由于日志可能延后而导致有一小段时间应用不会被隔离的问题\n "
},
{
"path": "storage_redirect/zh-hans/guide/enhanced_mode/install.md",
"chars": 1175,
"preview": "# 安装\n\n增强模块要求您的设备首先安装 Magisk。您可以从 [GitHub](https://github.com/topjohnwu/Magisk) 了解有关 Magisk 的更多信息。\n\n:::tip 提示\n从 Magisk v2"
},
{
"path": "storage_redirect/zh-hans/guide/faq/cant_find_app.md",
"chars": 286,
"preview": "# 无法找到一些应用\n\n只有请求了读取<b>和</b>写入存储权限的应用会被显示(换句话说,只请求读取存储权限或没有请求存储权限的应用不会显示)。\n\n## 使用 root/adb 的应用\n\n使用 root 或 adb 的应用可以直接以 ro"
},
{
"path": "storage_redirect/zh-hans/guide/faq/how_to_document.md",
"chars": 510,
"preview": "# 如何使用文档(文件)应用\n\n文档应用是 Android 系统的一部分,好处是使用者可以借此方便地从各种来源(任何实现了 DocumentProvider 的应用,如 Google Drive)存取文件。\n但坏处是文档应用可能有些难用。此"
},
{
"path": "storage_redirect/zh-hans/guide/faq/how_to_report_problems.md",
"chars": 465,
"preview": "# 回报问题\n\n该文档将教你如何回报问题。\n\n> 对于仅限于特定应用的问题(如无法在应用中找到图片),大概率是设定不正确,请先自行尝试阅读其他文档了解如何正确设置。\n\n1. 确认你正在使用最近的版本的应用\n2. 描述应用版本(例如 v4.1"
},
{
"path": "storage_redirect/zh-hans/guide/tutorial.md",
"chars": 6038,
"preview": "# 教程\n\n## 启用隔离后会发生什么?\n\n假设存在一个应用 ExampleApp(包名为 `com.example`),它使用了有滥用存储空间行为的 SDK(假设它会创建 `bad_sdk` 文件夹)。那么在授予 ExampleApp 存"
},
{
"path": "storage_redirect/zh-hant/README.md",
"chars": 381,
"preview": "---\nhome: true\nheroImage: /logo.png\nactionText: 下載\nactionLink: /zh-hant/download.html\nsecondaryActionText: 瞭解更多\nsecondar"
},
{
"path": "storage_redirect/zh-hant/changelog.md",
"chars": 24240,
"preview": "# Changelog\n\n## 8.4.3 (2023-04-12)\n\n- 修復了在 Android 10 以上,沒有寫儲存權限的應用程式沒有顯示「匯出被隔離的檔案 & 重新導系統提供程式」選項的問題\n \n 在 Android 10 以"
},
{
"path": "storage_redirect/zh-hant/download.md",
"chars": 404,
"preview": "# 下載\n\n**需求:** 已 root 的 Android 6.0 以上裝置\n\n[Google Play](https://play.google.com/store/apps/details?id=moe.shizuku.redirec"
},
{
"path": "storage_redirect/zh-hant/guide/README.md",
"chars": 2437,
"preview": "# 介紹\n\n截至本文編寫的時間(2023-03-06),在 Android 系統中應用程式對公共儲存空間的濫用仍然是一個沒有解決的問題。\n\n儲存空間隔離致力於在儘可能小或不影響應用程式功能的前提下,解決這一問題。\n\n要清楚地說明這個問題,我"
},
{
"path": "storage_redirect/zh-hant/guide/advanced/shared_user_id.md",
"chars": 899,
"preview": "# 程式組\n\nAndroid 系統的 Shared User ID 機制允許多個應用程式享有相同的 Linux user ID 及 Android 權限,相互訪問檔案甚至執行在同一個行程。這些應用程式需要有具有相同簽名。Shared Use"
},
{
"path": "storage_redirect/zh-hant/guide/advanced/technical_details_export_isolated_files.md",
"chars": 901,
"preview": "# 技術細節(匯出被隔離的檔案)\n\n假設有一個應用程式 `com.example` 儲存圖片至 `images` 資料夾。建立了一條來源資料夾 `images`,目標資料夾 `Pictures/Example` 的規則。\n\n```\n/sto"
},
{
"path": "storage_redirect/zh-hant/guide/compatibility/README.md",
"chars": 250,
"preview": "# 概覽\n\n* [Samsung](./samsung.md)\n* [Meizu](./meizu.md)\n* [Xiaomi (MIUI)](./miui.md)\n* 其他\n\n * log 被關閉問題\n\n 在「開發者設定」中檢查 "
},
{
"path": "storage_redirect/zh-hant/guide/compatibility/meizu.md",
"chars": 113,
"preview": "# Meizu\n\n如果你可以使用 Magisk,你不會遇到問題。\n\n如果你不能使用 Magisk,不要為系統的「設定」程式(或其所屬的[程式組](./../advanced/shared_user_id.html))啟用隔離。"
},
{
"path": "storage_redirect/zh-hant/guide/compatibility/miui.md",
"chars": 652,
"preview": "# Xiaomi(MIUI)\n\nMIUI 有一系列**預設啟用**的限制。然而這些限制過於離譜,應用程式正常的功能經常因此被破壞。\n\n更令人生氣的是,這些限制由 MIUI 的線上規則控制,並且對於 WeChat 這樣在中國大陸地區流行的應用"
},
{
"path": "storage_redirect/zh-hant/guide/compatibility/samsung.md",
"chars": 144,
"preview": "# Samsung\n\n由於未知原因,在部分 Samsung 裝置上,以 root 使用者中執行 64 位可執行程式,其中 `exec` 函式必定會 `Permission denied`。\n\n解決方法很簡單,解除安裝後安裝 [arm 版本]"
},
{
"path": "storage_redirect/zh-hant/guide/contribute.md",
"chars": 224,
"preview": "# 貢獻線上規則\n\n目前需要人工在 GitHub 建立 issue。請按照下面的步驟進行。\n\n1. 如果你沒有 [GitHub](https://github.com/) 賬號,建立一個\n2. [建立新的 issue](https://gi"
},
{
"path": "storage_redirect/zh-hant/guide/enhanced_mode/README.md",
"chars": 351,
"preview": "# 為何增強模式是必要的?\n\n-----------------------\n\n增強模式提供以下功能:\n\n1. 不再需要依賴 logcat 偵測 app 程序建立\n - 規避由於日誌可能延後而導致有一小段時間應用程式不會被隔離的問題\n "
},
{
"path": "storage_redirect/zh-hant/guide/enhanced_mode/install.md",
"chars": 1165,
"preview": "# 安裝\n\n增強模組要求您的裝置首先安裝 Magisk。您可以從 [GitHub](https://github.com/topjohnwu/Magisk) 瞭解有關 Magisk 的更多資訊。\n\n:::tip 提示\n從 Magisk v2"
},
{
"path": "storage_redirect/zh-hant/guide/faq/cant_find_app.md",
"chars": 310,
"preview": "# 無法找到一些應用程式\n\n只有請求了讀取<b>和</b>寫入儲存權限的應用程式會被顯示(換句話說,只請求讀取儲存權限或沒有請求儲存權限的應用程式不會顯示)。\n\n## 使用 root/adb 的應用程式\n\n使用 root 或 adb 的應用"
},
{
"path": "storage_redirect/zh-hant/guide/faq/how_to_document.md",
"chars": 509,
"preview": "# 如何使用檔案程式\n\n檔案程式是 Android 系統的一部分,好處是使用者可以藉此方便地從各種來源(任何實現了 DocumentProvider 的程式,如 Google Drive)讀取檔案。\n但壞處是檔案程式可能有些難用。此幫助將教"
},
{
"path": "storage_redirect/zh-hant/guide/faq/how_to_report_problems.md",
"chars": 475,
"preview": "# 回報問題\n\n該文件將教你如何回報問題。\n\n> 對於僅限於特定應用程式的問題(如無法在應用程式中找到圖片),大概率是設定不正確,請先自行嘗試閱讀其他文件瞭解如何正確設定。\n\n1. 確認你正在使用最近的版本的應用程式\n2. 描述應用程式版本"
},
{
"path": "storage_redirect/zh-hant/guide/tutorial.md",
"chars": 6025,
"preview": "# 教程\n\n## 啟用隔離後會發生什麼?\n\n假設存在一個應用程式 ExampleApp(包名為 `com.example`),它使用了有濫用儲存空間行為的 SDK(假設它會建立 `bad_sdk` 資料夾)。那麼在授予 ExampleApp"
},
{
"path": "webhooks/.gitignore",
"chars": 44,
"preview": "/node_modules\npackage-lock.json\nconfig.json\n"
},
{
"path": "webhooks/index.js",
"chars": 4885,
"preview": "console.log(`CWD: ${process.cwd()}`)\n\nconst { port, secret, sites, cf_email, cf_key, cf_zone_id } = require(`${process.c"
},
{
"path": "webhooks/package.json",
"chars": 586,
"preview": "{\n \"name\": \"webhooks\",\n \"version\": \"0.1.0\",\n \"description\": \"\",\n \"main\": \"index.js\",\n \"scripts\": {\n \"start-debug"
},
{
"path": "www/.gitignore",
"chars": 15,
"preview": "/.vuepress/dist"
},
{
"path": "www/.vuepress/config.js",
"chars": 5019,
"preview": "const moment = require('moment')\nconst langMap = {\n \"zh-Hans\": \"zh-cn\",\n \"zh-Hant\": \"zh-tw\"\n}\n\nvar timestampCache = {}"
},
{
"path": "www/.vuepress/public/robots.txt",
"chars": 93,
"preview": "User-Agent: *\n\nDisallow: /zh-hans/transfer_china.html\nDisallow: /zh-hans/use_google_play.html"
},
{
"path": "www/.vuepress/theme/components/Home.vue",
"chars": 6272,
"preview": "<template>\n <main class=\"home\" aria-labelledby=\"main-title\">\n <header class=\"hero\">\n <!--<img\n class=\"ba"
},
{
"path": "www/.vuepress/theme/components/SidebarLink.vue",
"chars": 3163,
"preview": "<script>\nimport { isActive, hashRE, groupHeaders } from '@parent-theme/util'\n\nexport default {\n functional: true,\n\n pr"
},
{
"path": "www/.vuepress/theme/index.js",
"chars": 56,
"preview": "module.exports = {\n extend: '@vuepress/theme-default'\n}"
},
{
"path": "www/.vuepress/theme/layouts/Layout.vue",
"chars": 176,
"preview": "<template>\n <ParentLayout/>\n</template>\n\n<script>\nimport ParentLayout from '@parent-theme/layouts/Layout.vue'\nexport de"
},
{
"path": "www/.vuepress/theme/styles/index.styl",
"chars": 264,
"preview": "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 Ro"
},
{
"path": "www/.vuepress/theme/styles/palette.styl",
"chars": 89,
"preview": "$accentColor = #D81B60\n$textColor = #2c3e50\n$borderColor = #eaecef\n$codeBgColor = #282c34"
},
{
"path": "www/README.md",
"chars": 1681,
"preview": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: Storage Isolation\n details: Give a"
},
{
"path": "www/contribute_translation.md",
"chars": 496,
"preview": "# Contribute translation\n\nRikkaApps uses self-hosted Weblate as a translation platform. Currently, we are moving the tra"
},
{
"path": "www/knowledge/exit_on_start.md",
"chars": 830,
"preview": "# Exit on start\n\nStorage Isolation, AppOps, and NoPopping have anti-tampering mechanisms. Once tampering is detected, th"
},
{
"path": "www/knowledge/google_play_purchase.md",
"chars": 2314,
"preview": "# Purchase (restore) issues on Google Play\n\nThe whole purchase process happens in Google Play, **the app developer has z"
},
{
"path": "www/privacy_policy.md",
"chars": 3167,
"preview": "---\nnavbar: false\n---\n\n# Privacy Policy\n\nThe protection of your data is of particular concern to us. Therefore, we proce"
},
{
"path": "www/zh-hans/README.md",
"chars": 1429,
"preview": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: 存储空间隔离\n details: 让应用有隔离存储,再也不为设计不佳"
},
{
"path": "www/zh-hans/contribute_translation.md",
"chars": 293,
"preview": "# 参与翻译\n\nRikkaApps 使用自行托管的 Weblate 作为翻译平台。目前,我们正在将翻译移动至该平台。\n\n1. 进入 <https://weblate.rikka.app/>\n2. 通过 GitHub 登录\n3. 查看所有项目"
},
{
"path": "www/zh-hans/knowledge/exit_on_start.md",
"chars": 365,
"preview": "# 启动后立刻退出\n\nStorage Isolation、AppOps 和 NoPopping 有反篡改机制。一旦检测到篡改,应用程序会在启动后立刻退出。\n\n篡改行为包括但不限于:\n\n* 重新签名\n* 在虚拟环境中运行\n* 为应用程序启用 "
},
{
"path": "www/zh-hans/knowledge/google_play_purchase.md",
"chars": 1037,
"preview": "# Google Play 购买问题\n\n整个购买过程都发生在 Google Play 中,**应用开发者无法控制它**,因此所有这些解决方案都是经验之谈。\n\n### 多账号问题\n\n如果你登录了多个账号,Play 商店可能会使用错误的账号。应"
},
{
"path": "www/zh-hant/README.md",
"chars": 1435,
"preview": "---\nhome: true\nheroImage: /logo.webp\nbackgroundImage: /background.png\napps:\n- title: 儲存空間隔離\n details: 讓應用有隔離儲存,再也不為設計不佳"
},
{
"path": "www/zh-hant/contribute_translation.md",
"chars": 293,
"preview": "# 參與翻譯\n\nRikkaApps 使用自行架設的 Weblate 作為翻譯平臺。目前,我們正在將翻譯移動至該平臺。\n\n1. 進入 <https://weblate.rikka.app/>\n2. 透過 GitHub 登入\n3. 檢視所有專案"
},
{
"path": "www/zh-hant/knowledge/exit_on_start.md",
"chars": 368,
"preview": "# 啟動後立刻退出\n\nStorage Isolation、AppOps 和 NoPopping 有反篡改機制。一旦檢測到篡改,應用程式會在啟動後立刻退出。\n\n篡改行為包括但不限於:\n\n* 重新簽名\n* 在虛擬環境中執行\n* 為應用程式啟用 "
},
{
"path": "www/zh-hant/knowledge/google_play_purchase.md",
"chars": 1043,
"preview": "# Google Play 購買問題\n\n整個購買過程都發生在 Google Play 中,**應用程式的開發人員無法控制它**,因此所有這些解決方案都是經驗之談。\n\n### 多賬號問題\n\n如果你登入了多個賬號,Play 商店可能會使用錯誤的"
}
]
About this extraction
This page contains the full source code of the RikkaApps/websites GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 177 files (361.6 KB), approximately 134.9k tokens, and a symbol index with 29 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.
Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.