Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Sign in / Register
Toggle navigation
S
Super File Manager
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
wanglei
Super File Manager
Commits
4a0909ac
Commit
4a0909ac
authored
May 30, 2024
by
wanglei
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Initial commit
parent
3ba89098
Show whitespace changes
Inline
Side-by-side
Showing
40 changed files
with
2172 additions
and
119 deletions
+2172
-119
build.gradle
app/build.gradle
+7
-2
google-services.json
app/google-services.json
+29
-0
proguard.py
app/proguard.py
+1815
-0
ExampleInstrumentedTest.kt
...java/com/base/superfilemanager/ExampleInstrumentedTest.kt
+1
-1
AndroidManifest.xml
app/src/main/AndroidManifest.xml
+4
-0
BaseApplication.kt
...rc/main/java/com/base/superfilemanager/BaseApplication.kt
+1
-1
MyApplication.kt
app/src/main/java/com/base/superfilemanager/MyApplication.kt
+1
-1
FileCategoryActivity.kt
...om/base/superfilemanager/activity/FileCategoryActivity.kt
+19
-26
MainActivity.kt
...n/java/com/base/superfilemanager/activity/MainActivity.kt
+4
-4
PrivacyWebActivity.kt
.../com/base/superfilemanager/activity/PrivacyWebActivity.kt
+39
-0
PrivacyAgreementManager.kt
...perfilemanager/activity/splash/PrivacyAgreementManager.kt
+65
-0
ProgressManager.kt
.../base/superfilemanager/activity/splash/ProgressManager.kt
+2
-2
SplashActivity.kt
...m/base/superfilemanager/activity/splash/SplashActivity.kt
+21
-12
FileBrowseAdapter.kt
...va/com/base/superfilemanager/adapter/FileBrowseAdapter.kt
+5
-5
FileCategoryAdapter.kt
.../com/base/superfilemanager/adapter/FileCategoryAdapter.kt
+7
-7
FIleBean.kt
app/src/main/java/com/base/superfilemanager/bean/FIleBean.kt
+1
-1
FileCategoryBean.kt
...n/java/com/base/superfilemanager/bean/FileCategoryBean.kt
+1
-1
ImageDataBean.kt
...main/java/com/base/superfilemanager/bean/ImageDataBean.kt
+1
-1
FileCategoryFragment.kt
...om/base/superfilemanager/fragment/FileCategoryFragment.kt
+9
-9
AESHelper.kt
...rc/main/java/com/base/superfilemanager/helps/AESHelper.kt
+2
-2
AESTextView.kt
.../main/java/com/base/superfilemanager/helps/AESTextView.kt
+2
-2
BaseActivity.kt
...main/java/com/base/superfilemanager/helps/BaseActivity.kt
+3
-3
BaseFragment.kt
...main/java/com/base/superfilemanager/helps/BaseFragment.kt
+1
-1
ConfigHelper.kt
...main/java/com/base/superfilemanager/helps/ConfigHelper.kt
+4
-4
EventHelper.kt
.../main/java/com/base/superfilemanager/helps/EventHelper.kt
+3
-2
KotlinExt.kt
...rc/main/java/com/base/superfilemanager/helps/KotlinExt.kt
+2
-2
FileEx.kt
.../main/java/com/base/superfilemanager/helps/file/FileEx.kt
+1
-1
FileHelps.kt
...in/java/com/base/superfilemanager/helps/file/FileHelps.kt
+4
-4
ImageHelper.kt
.../java/com/base/superfilemanager/helps/file/ImageHelper.kt
+2
-2
MediaStoreEx.kt
...java/com/base/superfilemanager/helps/file/MediaStoreEx.kt
+1
-1
DialogViews.kt
...c/main/java/com/base/superfilemanager/view/DialogViews.kt
+3
-3
FileDeleteDialog.kt
...n/java/com/base/superfilemanager/view/FileDeleteDialog.kt
+3
-3
XmlEx.kt
app/src/main/java/com/base/superfilemanager/view/XmlEx.kt
+1
-1
qdylogo.png
app/src/main/res/drawable-xxhdpi/qdylogo.png
+0
-0
splash_bp.xml
app/src/main/res/drawable/splash_bp.xml
+5
-6
activity_layout_web_privacy.xml
app/src/main/res/layout/activity_layout_web_privacy.xml
+40
-0
activity_splash.xml
app/src/main/res/layout/activity_splash.xml
+60
-7
strings.xml
app/src/main/res/values/strings.xml
+1
-0
ExampleUnitTest.kt
...rc/test/java/com/base/superfilemanager/ExampleUnitTest.kt
+1
-1
settings.gradle
settings.gradle
+1
-1
No files found.
app/build.gradle
View file @
4a0909ac
...
...
@@ -4,11 +4,11 @@ plugins {
}
android
{
namespace
'com.base.s
mart
filemanager'
namespace
'com.base.s
uper
filemanager'
compileSdk
34
defaultConfig
{
applicationId
"com.base.s
mart
filemanager"
applicationId
"com.base.s
uper
filemanager"
minSdk
24
targetSdk
34
versionCode
1
...
...
@@ -48,6 +48,11 @@ dependencies {
androidTestImplementation
libs
.
androidx
.
junit
androidTestImplementation
libs
.
androidx
.
espresso
.
core
implementation
(
"com.facebook.android:facebook-android-sdk:[8,9)"
)
implementation
platform
(
'com.google.firebase:firebase-bom:32.3.1'
)
implementation
'com.google.firebase:firebase-analytics:21.6.2'
implementation
(
"com.google.firebase:firebase-messaging"
)
implementation
(
"com.blankj:utilcodex:1.31.1"
)
implementation
(
"com.squareup.okhttp3:okhttp:4.9.0"
)
implementation
(
"com.squareup.okhttp3:logging-interceptor:4.9.0"
)
...
...
app/google-services.json
0 → 100644
View file @
4a0909ac
{
"project_info"
:
{
"project_number"
:
"993178188325"
,
"project_id"
:
"testcleanmaster"
,
"storage_bucket"
:
"testcleanmaster.appspot.com"
},
"client"
:
[
{
"client_info"
:
{
"mobilesdk_app_id"
:
"1:993178188325:android:a7986c2607f23024825dcc"
,
"android_client_info"
:
{
"package_name"
:
"com.base.superfilemanager"
}
},
"oauth_client"
:
[],
"api_key"
:
[
{
"current_key"
:
"AIzaSyCY5uqNx8qS5ZPvSIknbh2nH2v5vjzCmPI"
}
],
"services"
:
{
"appinvite_service"
:
{
"other_platform_oauth_client"
:
[]
}
}
}
],
"configuration_version"
:
"1"
}
\ No newline at end of file
app/proguard.py
0 → 100644
View file @
4a0909ac
import
json
import
os
import
random
import
re
import
shutil
from
base64
import
b64encode
,
b64decode
import
cv2
import
numpy
as
np
import
regex
as
re2
from
Cryptodome.Cipher
import
AES
from
Cryptodome.Random
import
get_random_bytes
import
string
import
random
def
encrypt
(
content
):
try
:
iv
=
get_random_bytes
(
12
)
cipher
=
AES
.
new
(
aesKey
.
encode
(
'utf-8'
),
AES
.
MODE_GCM
,
nonce
=
iv
)
encrypt_data
,
tag
=
cipher
.
encrypt_and_digest
(
content
.
encode
(
'utf-8'
))
result
=
iv
+
encrypt_data
+
tag
return
b64encode
(
result
)
.
decode
(
'utf-8'
)
except
Exception
as
e
:
print
(
'error: '
+
str
(
e
))
return
content
def
decrypt
(
content
):
try
:
combined
=
b64decode
(
content
.
encode
(
'utf-8'
))
iv
=
combined
[:
12
]
tag
=
combined
[
-
16
:]
encrypt_data
=
combined
[
12
:
-
16
]
cipher
=
AES
.
new
(
aesKey
.
encode
(
'utf-8'
),
AES
.
MODE_GCM
,
nonce
=
iv
)
decrypt_data
=
cipher
.
decrypt_and_verify
(
encrypt_data
,
tag
)
return
decrypt_data
.
decode
(
'utf-8'
)
except
(
ValueError
,
KeyError
)
as
e
:
print
(
e
)
return
content
def
get_classes_impl
(
result
,
class_type
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
get_classes_impl
(
result
,
class_type
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
in
class_type
:
result
.
append
(
path_join
)
def
get_classes
(
class_type
=
None
):
if
class_type
is
None
:
class_type
=
[
"kt"
,
"java"
]
result
=
[]
get_classes_impl
(
result
,
class_type
)
return
result
def
find_text_impl
(
reg
,
result
,
skip_name
,
path
,
is_one
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
if
is_one
and
len
(
result
)
>
0
:
return
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
find_text_impl
(
reg
,
result
,
skip_name
,
path_join
,
is_one
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
.
split
(
'.'
)[
-
1
]
in
[
'py'
]:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
extend
(
findall
)
def
find_text
(
reg
,
path
=
'.'
,
is_one
=
False
,
skip_name
=
None
):
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
if
os
.
path
.
isdir
(
path
):
find_text_impl
(
reg
,
result
,
skip_name
,
path
,
is_one
)
else
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
f
.
readable
():
try
:
text
=
f
.
read
()
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
extend
(
findall
)
except
ValueError
:
pass
if
is_one
:
if
len
(
result
)
>
0
:
return
result
[
0
]
else
:
return
None
return
result
def
find_file_impl
(
reg
,
result
,
skip_name
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
if
len
(
result
)
>
0
:
return
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
find_file_impl
(
reg
,
result
,
skip_name
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
not
in
[
"pro"
]:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
append
(
path_join
)
def
find_file
(
reg
,
path
=
'.'
,
skip_name
=
None
):
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
if
os
.
path
.
isdir
(
path
):
find_file_impl
(
reg
,
result
,
skip_name
,
path
)
else
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
f
.
readable
():
try
:
text
=
f
.
read
()
findall
=
re
.
findall
(
reg
,
text
)
if
len
(
findall
)
>
0
:
result
.
append
(
path
)
except
ValueError
:
pass
return
result
[
0
]
if
len
(
result
)
>
0
else
""
def
get_class_path
(
path
):
with
open
(
path
,
'r'
)
as
f
:
text
=
f
.
read
()
package
=
re
.
search
(
'package (.*?)
\\
s'
,
text
)
.
group
(
1
)
name
=
os
.
path
.
basename
(
path
)
name
=
name
[:
name
.
rfind
(
'.'
)]
return
package
+
'.'
+
name
def
replace_map_text
(
mapping
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
replace_map_text
(
mapping
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
reverse
=
sorted
(
list
(
mapping
.
keys
()),
key
=
len
,
reverse
=
True
)
for
name
in
reverse
:
text
=
text
.
replace
(
str
(
name
),
mapping
[
name
])
f
.
write
(
text
)
def
sub_map_text
(
mapping
,
is_reverse
=
True
,
path
=
'.'
,
skip_type
=
None
,
skip_name
=
None
):
if
len
(
mapping
)
==
0
:
return
[]
if
skip_type
is
None
:
skip_type
=
[]
if
skip_name
is
None
:
skip_name
=
[]
result
=
[]
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
,
path
)
return
result
def
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
=
True
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
sub_map_text_impl
(
mapping
,
result
,
skip_type
,
skip_name
,
is_reverse
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
if
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
in
skip_type
:
continue
is_skip
=
False
for
j
in
skip_name
:
if
j
in
i
:
is_skip
=
True
break
if
is_skip
:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
reverse
=
sorted
(
list
(
mapping
.
keys
()),
key
=
len
,
reverse
=
is_reverse
)
text_result
=
text
for
name
in
reverse
:
text_result
=
re2
.
sub
(
str
(
name
),
mapping
[
name
],
text_result
)
if
text_result
!=
text
:
result
.
append
(
path_join
)
f
.
write
(
text_result
)
def
replace_text
(
old
,
new
,
path
=
'.'
):
listdir
=
os
.
listdir
(
path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
if
path
.
endswith
(
'.'
)
and
i
in
[
"build"
,
"debug"
,
"release"
]:
continue
if
path
.
endswith
(
'src'
)
and
i
in
[
"androidTest"
,
"test"
]:
continue
replace_text
(
old
,
new
,
path_join
)
elif
os
.
path
.
isfile
(
path_join
):
if
path
.
endswith
(
'.'
)
and
os
.
path
.
splitext
(
i
)[
-
1
][
1
:]
not
in
[
"pro"
]:
continue
with
open
(
path_join
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
if
not
f
.
readable
():
continue
try
:
text
=
f
.
read
()
except
ValueError
:
continue
with
open
(
path_join
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
.
replace
(
old
,
new
))
def
get_random_package
():
packages
=
[
get_random_string
(
4
)
for
_
in
range
(
get_random_int
(
1
,
3
))]
return
'.'
.
join
(
packages
)
def
check_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'dir'
,
{})
packages
=
find_text
(
'package (.*?)[;]?
\\
s'
,
'src'
)
packages
.
append
(
applicationId
)
packages
=
sorted
(
set
(
packages
),
key
=
packages
.
index
)
packages
.
sort
(
key
=
len
)
mapping
=
{}
for
i
in
packages
:
if
applicationId
not
in
i
:
continue
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_package
()
value
=
mapping
.
get
(
i
[:
i
.
rfind
(
'.'
)])
if
value
is
not
None
:
mapping
[
i
]
=
value
+
'.'
+
mapping
[
i
]
loads
[
"dir"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_class_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'class'
,
{})
mapping
=
{}
classes
=
get_classes
()
for
i
in
classes
:
if
'_D'
in
i
:
continue
name
=
os
.
path
.
basename
(
i
)
name
=
name
[:
name
.
rfind
(
'.'
)]
value
=
old_mapping
.
get
(
name
)
if
value
is
not
None
:
mapping
[
name
]
=
value
continue
mapping
[
name
]
=
get_title
(
get_random_string
(
4
),
True
)
loads
[
"class"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_type_ids_mapping
(
ids_type
):
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
ids_type
+
"_ids"
,
{})
mapping
=
{}
type_ids
=
find_text
(
'<'
+
ids_type
+
' name="(.*?)".*?>'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
type_ids
:
if
i
.
endswith
(
'_D'
):
continue
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_string
(
5
,
False
)
type_ids
=
find_text
(
'<item name="(.*?)".*? type="'
+
ids_type
+
'">'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
type_ids
:
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
mapping
[
i
]
=
get_random_string
(
5
,
False
)
if
len
(
mapping
)
!=
0
:
loads
[
ids_type
+
"_ids"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_styleable_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
"styleable"
,
{})
mapping
=
{}
styleables
=
find_text
(
'<declare-styleable name=".*?">[
\\
s
\\
S]*?</declare-styleable>'
)
for
i
in
styleables
:
styleable_id
=
re
.
findall
(
'<declare-styleable name="(.*?)">'
,
i
)[
0
]
mapping
[
styleable_id
]
=
old_mapping
.
get
(
styleable_id
,
get_random_string
(
5
,
False
))
styleables_attr
=
re
.
findall
(
'<attr name="(.*?)".*?/>'
,
i
)
for
attr
in
styleables_attr
:
mapping
[
attr
+
'_A'
]
=
old_mapping
.
get
(
attr
+
'_A'
,
get_random_string
(
5
))
if
len
(
mapping
)
!=
0
:
loads
[
"styleable"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_ids_type
(
ids_type
):
type_ids_mapping
=
check_type_ids_mapping
(
ids_type
)
if
len
(
type_ids_mapping
)
==
0
:
return
print
(
type_ids_mapping
)
sub_map
=
{}
for
i
in
type_ids_mapping
:
sub_map
[
'<'
+
ids_type
+
' name="'
+
i
+
'"'
]
=
'<'
+
ids_type
+
' name="'
+
type_ids_mapping
[
i
]
+
'"'
sub_map
[
'<item name="'
+
i
+
'"(.*? type="'
+
ids_type
+
'")>'
]
=
\
'<item name="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<1>>'
sub_map
[
'(?<=[^
\\
.])R
\\
.'
+
ids_type
+
'
\\
.'
+
i
+
'(?=
\\
W)'
]
=
'R.'
+
ids_type
+
'.'
+
type_ids_mapping
[
i
]
sub_map
[
'(?<=>|")@'
+
ids_type
+
'/'
+
i
+
'(?=<|")'
]
=
'@'
+
ids_type
+
'/'
+
type_ids_mapping
[
i
]
sub_map
[
'<'
+
ids_type
+
'(.*?) parent="'
+
i
+
'"(.*?)>'
]
=
\
'<'
+
ids_type
+
'
\\
g<1> parent="'
+
type_ids_mapping
[
i
]
+
'"
\\
g<2>>'
sub_map_text
(
sub_map
)
def
check_strings_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'strings'
,
{})
string_values
=
find_text
(
'<string name="(.*?)".*?>(.*?)</string>'
,
get_path
(
'.
\\
src
\\
main
\\
res
\\
values'
))
strings
=
[]
for
i
in
string_values
:
if
i
[
0
]
.
endswith
(
'___'
)
or
i
[
0
]
in
[
'app_name'
,
'facebook_app_id'
]:
continue
if
mapping
.
get
(
i
[
1
])
is
not
None
:
continue
strings
.
append
(
i
[
1
])
for
i
in
strings
:
mapping
[
i
]
=
encrypt
(
i
)
loads
[
"strings"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_view_ids_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'view_ids'
,
{})
view_ids
=
find_text
(
'"
\\
@
\\
+id/(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
for
i
in
view_ids
:
if
i
==
'root'
:
continue
key
=
get_title
(
i
)
if
mapping
.
get
(
key
)
is
not
None
:
continue
mapping
[
key
]
=
get_random_string
(
7
)
loads
[
"view_ids"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_layout_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'layout'
,
{})
layout_path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
)
listdir
=
os
.
listdir
(
layout_path
)
for
i
in
listdir
:
name
=
i
[:
i
.
rfind
(
'.'
)]
if
mapping
.
get
(
name
)
is
not
None
:
continue
mapping
[
name
]
=
get_random_string
(
6
)
loads
[
"layout"
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
check_res_mapping
(
res_type
):
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
res_type
,
{})
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
if
not
i
.
startswith
(
res_type
):
continue
for
j
in
os
.
listdir
(
os
.
path
.
join
(
res_path
,
i
)):
if
j
.
startswith
(
'book_'
):
continue
if
j
.
endswith
(
'.9.png'
):
name
=
j
[:
-
len
(
'.9.png'
)]
else
:
name
=
j
.
rsplit
(
'.'
,
1
)[
0
]
if
mapping
.
get
(
name
)
is
not
None
:
continue
mapping
[
name
]
=
get_random_string
(
8
)
if
len
(
mapping
)
!=
0
:
loads
[
res_type
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
get_random_string
(
length
=
8
,
is_ascii
=
True
):
s
=
''
for
i
in
range
(
length
):
if
is_ascii
:
s
+=
chr
(
random
.
randint
(
0
,
25
)
+
ord
(
'a'
))
else
:
s
+=
chr
(
random
.
randrange
(
0x0780
,
0x07A5
+
1
))
return
s
def
get_random_int
(
a
=
0
,
b
=
10000
):
return
random
.
randint
(
a
,
b
)
def
get_dictionary_string
(
length
=
10
):
random_str
=
random
.
choice
(
string
.
ascii_letters
)
random_str
+=
''
.
join
(
random
.
choice
(
string
.
ascii_letters
+
string
.
digits
)
for
_
in
range
(
length
-
1
))
return
random_str
def
check_obfuscation_dictionary
():
if
not
os
.
path
.
exists
(
'dictionary.txt'
):
dictionary
=
set
()
while
len
(
dictionary
)
!=
5000
:
dictionary
.
add
(
get_dictionary_string
())
with
open
(
'dictionary.txt'
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
'
\n
'
.
join
(
dictionary
))
with
open
(
'proguard-rules.pro'
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
'-obfuscationdictionary'
in
text
:
return
text
+=
'
\n
-obfuscationdictionary dictionary.txt'
text
+=
'
\n
-classobfuscationdictionary dictionary.txt'
text
+=
'
\n
-packageobfuscationdictionary dictionary.txt'
with
open
(
'proguard-rules.pro'
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
mkdir
(
dir_path
):
try
:
os
.
makedirs
(
dir_path
)
except
OSError
:
pass
def
replace_click_method
():
try
:
path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
file
=
find_file
(
'fun View.setTrackedOnClickListener'
,
path
)
if
file
:
class_path
=
get_class_path
(
file
)
+
'.setTrackedOnClickListener'
# java类不能直接使用扩展函数
sub_map_text
({
'([.@])setOnClickListener'
:
'
\\
g<1>setTrackedOnClickListener'
,
},
path
=
path
,
skip_type
=
[
'java'
])
add_import
(
class_path
,
get_classes
([
'kt'
]))
except
IndexError
:
return
def
deal_code
():
# 替换点击事件
replace_click_method
()
# 生成包映射文件
mapping
=
check_mapping
()
packages
=
list
(
mapping
.
keys
())
print
(
mapping
)
# 移动文件
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
for
key
in
packages
:
key
=
str
(
key
)
old_path
=
get_path
(
root_path
+
'
\\
'
+
key
.
replace
(
'.'
,
'
\\
'
))
new_path
=
get_path
(
root_path
+
'
\\
'
+
mapping
[
key
]
.
replace
(
'.'
,
'
\\
'
))
if
not
os
.
path
.
exists
(
old_path
):
mkdir
(
old_path
)
if
not
os
.
path
.
exists
(
new_path
):
mkdir
(
new_path
)
listdir
=
os
.
listdir
(
old_path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
old_path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
continue
shutil
.
move
(
path_join
,
os
.
path
.
join
(
new_path
,
i
))
shutil
.
rmtree
(
get_path
(
root_path
+
'
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)]))
# 修改manifest
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
findall
=
re
.
findall
(
'android:name=(".*?")'
,
text
)
for
i
in
findall
:
if
i
.
startswith
(
'".'
):
text
=
text
.
replace
(
i
,
'"'
+
applicationId
+
i
[
1
:
-
1
]
+
'"'
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
# 修改依赖
sub_map
=
{}
for
i
in
mapping
:
sub_map
[
'(?<=
\\
W)'
+
i
+
'(?=
\\
W)'
]
=
mapping
[
i
]
# 过滤修改
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.R(?=
\\
W)'
]
=
applicationId
+
'.R'
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.databinding(?=
\\
W)'
]
=
applicationId
+
'.databinding'
sub_map
[
'(?<=
\\
W)'
+
mapping
[
applicationId
]
+
'.BuildConfig(?=
\\
W)'
]
=
applicationId
+
'.BuildConfig'
sub_map_text
(
sub_map
)
# 根包名下 R 单独处理
new_path
=
get_path
(
root_path
+
'
\\
'
+
mapping
[
packages
[
0
]]
.
replace
(
'.'
,
'
\\
'
))
listdir
=
os
.
listdir
(
new_path
)
result_path
=
[]
for
i
in
listdir
:
if
os
.
path
.
isdir
(
os
.
path
.
join
(
new_path
,
i
)):
continue
result_path
.
append
(
os
.
path
.
join
(
new_path
,
i
))
add_import
(
applicationId
+
'.R'
,
result_path
)
add_import
(
applicationId
+
'.BuildConfig'
,
result_path
)
# 类名
class_mapping
=
check_class_mapping
()
classes
=
get_classes
()
print
(
class_mapping
)
for
i
in
classes
:
if
'_D'
in
i
:
continue
name
=
os
.
path
.
basename
(
i
)
name
=
name
[:
name
.
rfind
(
'.'
)]
shutil
.
move
(
i
,
i
.
replace
(
name
,
class_mapping
[
name
]))
sub_map
=
{}
for
i
in
class_mapping
:
sub_map
[
'(?<=
\\
W)'
+
i
+
'(?=
\\
W)'
]
=
class_mapping
[
i
]
sub_map_text
(
sub_map
)
# 混淆字典
check_obfuscation_dictionary
()
def
deal_res_type
(
res_type
):
type_mapping
=
check_res_mapping
(
res_type
)
if
len
(
type_mapping
)
==
0
:
return
print
(
type_mapping
)
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
if
not
i
.
startswith
(
res_type
):
continue
path_join
=
os
.
path
.
join
(
res_path
,
i
)
for
j
in
os
.
listdir
(
path_join
):
if
j
.
startswith
(
'book_'
):
continue
if
j
.
endswith
(
'.9.png'
):
name
=
j
[:
-
len
(
'.9.png'
)]
else
:
name
=
j
.
rsplit
(
'.'
,
1
)[
0
]
path
=
os
.
path
.
join
(
path_join
,
j
)
if
'.DS_Store'
not
in
path
:
shutil
.
move
(
path
,
path
.
replace
(
name
,
type_mapping
[
name
]))
sub_map
=
{}
for
i
in
type_mapping
:
sub_map
[
'R
\\
.'
+
res_type
+
'
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.'
+
res_type
+
'.'
+
type_mapping
[
i
]
+
'
\\
g<1>'
sub_map
[
'(>|")@'
+
res_type
+
'/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@'
+
res_type
+
'/'
+
type_mapping
[
i
]
+
'
\\
g<2>'
sub_map_text
(
sub_map
)
def
add_image_noise
(
path
):
try
:
image
=
cv2
.
imread
(
path
,
cv2
.
IMREAD_UNCHANGED
)
if
path
.
endswith
(
'.9.png'
):
return
# 添加随机噪声
noise
=
np
.
random
.
randint
(
0
,
2
,
image
.
shape
,
np
.
uint8
)
image
=
cv2
.
add
(
image
,
noise
)
new_path
=
path
.
rsplit
(
'.'
,
1
)[
0
]
+
'.webp'
cv2
.
imwrite
(
new_path
,
image
,
[
cv2
.
IMWRITE_WEBP_QUALITY
,
75
])
if
new_path
!=
path
:
os
.
remove
(
path
)
except
AttributeError
:
return
def
deal_image
():
res_path
=
get_path
(
'.
\\
src
\\
main
\\
res'
)
listdir
=
os
.
listdir
(
res_path
)
for
i
in
listdir
:
path_join
=
os
.
path
.
join
(
res_path
,
i
)
if
os
.
path
.
isdir
(
path_join
):
for
j
in
os
.
listdir
(
path_join
):
add_image_noise
(
os
.
path
.
join
(
path_join
,
j
))
def
get_title
(
string
,
is_all_upper
=
False
):
splits
=
string
.
split
(
'_'
)
s
=
''
for
i
in
range
(
len
(
splits
)):
if
i
==
0
and
not
is_all_upper
:
s
=
splits
[
i
]
elif
len
(
splits
[
i
])
>
0
:
s
+=
splits
[
i
][
0
]
.
upper
()
+
splits
[
i
][
1
:]
return
s
def
add_import
(
path
,
listfile
):
for
i
in
listfile
:
with
open
(
i
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
len
(
re
.
findall
(
'import '
+
path
,
text
))
!=
0
:
continue
if
i
.
endswith
(
'kt'
):
text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
path
+
'
\n
'
,
text
,
flags
=
re
.
S
)
elif
i
.
endswith
(
'java'
):
text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
path
+
';
\n
'
,
text
,
flags
=
re
.
S
)
with
open
(
i
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
check_class_string_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
mapping
=
loads
.
get
(
'class_string'
,
{})
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
if
os
.
path
.
basename
(
path
)
.
startswith
(
'AESHelper'
):
continue
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
strings
=
re
.
findall
(
'".*?[^
\\\\
]"'
,
re
.
sub
(
r'@[^)]*'
,
lambda
x
:
x
.
group
()
.
replace
(
'"'
,
"'"
),
result_text
))
last_string
=
''
for
string
in
strings
:
if
len
(
string
)
<=
4
or
string
.
isspace
()
or
\
string
[
1
:
-
1
]
in
[
'
\\\\
n'
,
'
\\\\
r'
,
'
\\\\\'
'
,
'
\\\\\\
"'
,
'
\\\\
?'
,
'&'
,
'UTF-8'
]:
continue
if
string
in
last_string
:
continue
start
=
text
.
find
(
string
)
if
start
==
-
1
:
continue
index
=
start
+
1
sign_stack
=
[
'"'
]
while
len
(
sign_stack
)
!=
0
:
if
text
[
index
]
==
'
\\
'
:
index
+=
1
elif
text
[
index
]
==
'"'
and
sign_stack
[
-
1
]
==
'"'
:
sign_stack
.
pop
()
elif
text
[
index
]
==
'"'
:
sign_stack
.
append
(
'"'
)
elif
text
[
index
]
==
'}'
and
sign_stack
[
-
1
]
==
'${'
:
sign_stack
.
pop
()
elif
text
[
index
-
1
:
index
+
1
]
==
'${'
:
sign_stack
.
append
(
'${'
)
index
+=
1
string
=
text
[
start
:
index
]
last_string
=
string
params
=
[]
result
=
string
if
'$'
in
string
:
count
=
0
last
=
-
1
res
=
[]
for
i
in
range
(
len
(
string
)):
if
last
==
-
1
and
string
[
i
]
==
'$'
:
if
count
==
0
:
last
=
i
elif
last
!=
-
1
:
if
string
[
i
]
==
'{'
:
count
+=
1
elif
string
[
i
]
==
'}'
:
count
-=
1
if
count
==
0
:
res
.
append
((
last
,
i
+
1
))
last
=
-
1
elif
count
==
0
:
last
=
-
1
for
i
in
re
.
findall
(
'
\\
$
\\
w*'
,
string
):
if
i
==
'$'
:
continue
find
=
string
.
find
(
i
)
res
.
append
((
find
,
find
+
len
(
i
)))
res
=
sorted
(
res
,
key
=
lambda
l
:
l
[
0
])
last_res
=
None
for
i
in
res
:
if
last_res
is
not
None
and
i
[
0
]
<
last_res
[
1
]:
continue
params
.
append
(
string
[
i
[
0
]:
i
[
1
]])
last_res
=
i
for
i
in
params
:
result
=
result
.
replace
(
i
,
"[str]"
)
result
=
result
[
1
:
-
1
]
.
replace
(
'
%
'
,
'
%%
'
)
.
replace
(
'
\\\\
'
,
'
\\
'
)
.
replace
(
'[str]'
,
'
%
s'
)
if
result
==
aesKey
:
continue
if
mapping
.
get
(
result
)
is
not
None
:
continue
mapping
[
result
]
=
get_random_string
(
5
,
False
)
+
'_D'
loads
[
'class_string'
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_class_string
():
# 获取映射
string_mapping
=
check_class_string_mapping
()
print
(
string_mapping
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
rfind
=
text
.
rfind
(
'
\n
'
)
text_result
=
text
[:
rfind
]
for
i
in
string_mapping
:
string
=
i
string
=
string
.
replace
(
'&'
,
'&'
)
string
=
string
.
replace
(
'?'
,
'
\\
?'
)
string
=
string
.
replace
(
'
\'
'
,
'
\\\'
'
)
text_result
+=
'
\n
<string name="'
+
string_mapping
[
i
]
+
'" translatable="false">'
+
string
+
'</string>'
text_result
+=
text
[
rfind
:]
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text_result
)
# 搜索 Int.string() 路径
file_path
=
find_file
(
'fun Int.string'
,
get_path
(
'.
\\
src
\\
main
\\
java'
))
class_path
=
get_class_path
(
file_path
)
+
'.string'
if
file_path
else
""
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
# 跳过 AESHelper 类中的字符串,避免嵌套
if
os
.
path
.
basename
(
path
)
.
startswith
(
'AESHelper'
):
continue
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
strings
=
re
.
findall
(
'".*?[^
\\\\
]"'
,
re
.
sub
(
r'@[^)]*'
,
lambda
x
:
x
.
group
()
.
replace
(
'"'
,
"'"
),
result_text
))
last_string
=
''
for
string
in
strings
:
if
len
(
string
)
<=
4
or
string
.
isspace
()
or
\
string
[
1
:
-
1
]
in
[
'
\\\\
n'
,
'
\\\\
r'
,
'
\\\\\'
'
,
'
\\\\\\
"'
,
'
\\\\
?'
,
'&'
,
'UTF-8'
]:
continue
if
string
in
last_string
:
continue
start
=
text
.
find
(
string
)
if
start
==
-
1
:
continue
index
=
start
+
1
sign_stack
=
[
'"'
]
while
len
(
sign_stack
)
!=
0
:
if
text
[
index
]
==
'
\\
'
:
index
+=
1
elif
text
[
index
]
==
'"'
and
sign_stack
[
-
1
]
==
'"'
:
sign_stack
.
pop
()
elif
text
[
index
]
==
'"'
:
sign_stack
.
append
(
'"'
)
elif
text
[
index
]
==
'}'
and
sign_stack
[
-
1
]
==
'${'
:
sign_stack
.
pop
()
elif
text
[
index
-
1
:
index
+
1
]
==
'${'
:
sign_stack
.
append
(
'${'
)
index
+=
1
# 得到完整字符串
string
=
text
[
start
:
index
]
last_string
=
string
# 参数
params
=
[]
result
=
string
# 处理字符串拼接
if
'$'
in
string
:
count
=
0
last
=
-
1
res
=
[]
for
i
in
range
(
len
(
string
)):
if
last
==
-
1
and
string
[
i
]
==
'$'
:
if
count
==
0
:
last
=
i
elif
last
!=
-
1
:
if
string
[
i
]
==
'{'
:
count
+=
1
elif
string
[
i
]
==
'}'
:
count
-=
1
if
count
==
0
:
res
.
append
((
last
,
i
+
1
))
last
=
-
1
elif
count
==
0
:
last
=
-
1
for
i
in
re
.
findall
(
'
\\
$
\\
w*'
,
string
):
if
i
==
'$'
:
continue
find
=
string
.
find
(
i
)
res
.
append
((
find
,
find
+
len
(
i
)))
res
=
sorted
(
res
,
key
=
lambda
l
:
l
[
0
])
last_res
=
None
for
i
in
res
:
if
last_res
is
not
None
and
i
[
0
]
<
last_res
[
1
]:
continue
params
.
append
(
string
[
i
[
0
]:
i
[
1
]])
last_res
=
i
for
i
in
params
:
result
=
result
.
replace
(
i
,
"[str]"
)
for
i
in
range
(
len
(
params
)):
if
params
[
i
][
1
]
==
'{'
:
params
[
i
]
=
params
[
i
][
2
:
-
1
]
else
:
params
[
i
]
=
params
[
i
][
1
:]
# 每个参数加上 toString
params
[
i
]
=
'('
+
params
[
i
]
+
').toString()'
# 拼接部分替换为 %s
result
=
result
[
1
:
-
1
]
.
replace
(
'
%
'
,
'
%%
'
)
.
replace
(
'
\\\\
'
,
'
\\
'
)
.
replace
(
'[str]'
,
'
%
s'
)
# aesKey 密钥不加密
if
result
==
aesKey
:
continue
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
'R.string.'
+
string_mapping
[
result
]
+
'.string('
+
', '
.
join
(
params
)
+
')'
)
# 添加 Int.string() 方法引用
if
class_path
:
if
len
(
re
.
findall
(
'import '
+
class_path
,
text
))
==
0
:
result_text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
class_path
+
'
\n
'
,
result_text
,
flags
=
re
.
S
)
# 添加资源 R 引用
if
len
(
re
.
findall
(
'import '
+
applicationId
+
'.R'
,
text
))
==
0
:
result_text
=
re
.
sub
(
'(package
\\
S+?
\\
s+?)(?=
\\
S)'
,
'
\\
g<1>import '
+
applicationId
+
'.R'
+
'
\n
'
,
result_text
,
flags
=
re
.
S
)
# 去除 const
result_text
=
re
.
sub
(
'const (val.*?R
\\
.string
\\
.
\\
S+?
\\
.string
\\
(
\\
))'
,
'
\\
g<1>'
,
result_text
)
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
def
check_xml_string_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_mapping
=
loads
.
get
(
'xml_string'
,
{})
strings
=
find_text
(
'android:text="(?<!@string/)([^@"]+?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
mapping
=
{}
for
i
in
strings
:
value
=
old_mapping
.
get
(
i
)
if
value
is
not
None
:
mapping
[
i
]
=
value
continue
# 添加 '_D' 结尾,资源混淆时过滤不用再次改名
mapping
[
i
]
=
get_random_string
(
5
,
False
)
+
'_D'
loads
[
'xml_string'
]
=
mapping
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
mapping
def
deal_xml_string
():
# 获取映射
string_mapping
=
check_xml_string_mapping
()
print
(
string_mapping
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
rfind
=
text
.
rfind
(
'
\n
'
)
text_result
=
text
[:
rfind
]
for
i
in
string_mapping
:
string
=
i
string
=
string
.
replace
(
'&'
,
'&'
)
string
=
string
.
replace
(
'?'
,
'
\\
?'
)
string
=
string
.
replace
(
'
\'
'
,
'
\\\'
'
)
text_result
+=
'
\n
<string name="'
+
string_mapping
[
i
]
+
'" translatable="false">'
+
string
+
'</string>'
text_result
+=
text
[
rfind
:]
with
open
(
get_path
(
'.
\\
src
\\
main
\\
res
\\
values
\\
strings.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text_result
)
sub_map
=
{}
for
i
in
string_mapping
:
sub_map
[
'(?<=android:text=")'
+
re
.
escape
(
i
)
+
'(?=")'
]
=
'@string/'
+
re
.
escape
(
string_mapping
[
i
])
# 替换时跳过通知布局
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
def
deal_code_string
():
# 处理布局文件中的明文字符串
deal_xml_string
()
# 处理代码文件中的明文字符串
deal_class_string
()
def
deal_res
():
# 添加字符串为 string 资源
deal_code_string
()
# 替换 TextView 为 AESTextView
aes_text_view
=
get_class_path
(
find_file
(
'class AESTextView'
,
get_path
(
'.
\\
src
\\
main
\\
java'
)))
sub_map
=
{
'(?<=<)TextView'
:
aes_text_view
,
'(?<=<)com.noober.background.view.BLTextView'
:
aes_text_view
}
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
),
skip_name
=
[
'notify'
,
'notity'
])
# 加密 string
strings_mapping
=
check_strings_mapping
()
print
(
strings_mapping
)
sub_map
=
{}
for
i
in
strings_mapping
:
sub_map
[
'<string(.*?)>'
+
re
.
escape
(
i
)
+
'</string>'
]
=
\
'<string
\\
g<1>>'
+
re
.
escape
(
strings_mapping
[
i
])
+
'</string>'
sub_map_text
(
sub_map
,
path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
values'
))
# 改 string id
deal_ids_type
(
'string'
)
# 改 color id
deal_ids_type
(
'color'
)
# 改 dimen id
deal_ids_type
(
'dimen'
)
# 改 style id
deal_ids_type
(
'style'
)
# 改 declare-styleable
styleable_mapping
=
check_styleable_mapping
()
print
(
styleable_mapping
)
sub_map
=
{}
styleables
=
find_text
(
'<declare-styleable name=".*?">[
\\
s
\\
S]*?</declare-styleable>'
)
for
i
in
styleables
:
result
=
i
styleable_id
=
re
.
findall
(
'<declare-styleable name="(.*?)">'
,
i
)[
0
]
result
=
result
.
replace
(
'<declare-styleable name="'
+
styleable_id
+
'">'
,
'<declare-styleable name="'
+
styleable_mapping
[
styleable_id
]
+
'">'
)
sub_map
[
'R
\\
.styleable
\\
.'
+
styleable_id
+
'(
\\
W)'
]
=
\
'R.styleable.'
+
styleable_mapping
[
styleable_id
]
+
'
\\
g<1>'
styleables_attr
=
re
.
findall
(
'<attr name="(.*?)".*?/>'
,
i
)
for
attr
in
styleables_attr
:
result
=
result
.
replace
(
'<attr name="'
+
attr
+
'"'
,
'<attr name="'
+
styleable_mapping
[
attr
+
'_A'
]
+
'"'
)
sub_map
[
'R
\\
.styleable
\\
.'
+
styleable_id
+
'_'
+
attr
+
'(
\\
W)'
]
=
\
'R.styleable.'
+
styleable_mapping
[
styleable_id
]
+
'_'
+
styleable_mapping
[
attr
+
'_A'
]
+
'
\\
g<1>'
sub_map
[
'app:'
+
attr
+
'='
]
=
'app:'
+
styleable_mapping
[
attr
+
'_A'
]
+
'='
sub_map
[
re
.
escape
(
i
)]
=
result
sub_map_text
(
sub_map
)
# 改 view id
view_ids
=
find_text
(
'"
\\
@
\\
+id/(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
res'
))
view_ids_mapping
=
check_view_ids_mapping
()
print
(
view_ids_mapping
)
sub_map
=
{}
for
i
in
view_ids
:
if
i
==
'root'
:
continue
key
=
get_title
(
i
)
sub_map
[
'(>|")@(
\\
+)?id/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@
\\
g<2>id/'
+
view_ids_mapping
[
key
]
+
'
\\
g<3>'
sub_map
[
'R
\\
.id
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.id.'
+
view_ids_mapping
[
key
]
+
'
\\
g<1>'
sub_map
[
'([bB]inding
\\
??(?:
\\
.
\\
w+)?
\\
??)
\\
.'
+
key
+
'(
\\
W)'
]
=
'
\\
g<1>.'
+
view_ids_mapping
[
key
]
+
'
\\
g<2>'
sub_map
[
'(?<=app:constraint_referenced_ids=".*?)'
+
i
+
'(?=.*?")'
]
=
view_ids_mapping
[
key
]
sub_map_text
(
sub_map
)
# 改 layout 文件名
layout_mapping
=
check_layout_mapping
()
print
(
layout_mapping
)
layout_path
=
get_path
(
'.
\\
src
\\
main
\\
res
\\
layout'
)
listdir
=
os
.
listdir
(
layout_path
)
for
i
in
listdir
:
name
=
i
[:
i
.
rfind
(
'.'
)]
if
layout_mapping
.
get
(
name
)
is
None
:
continue
path_join
=
os
.
path
.
join
(
layout_path
,
i
)
shutil
.
move
(
path_join
,
path_join
.
replace
(
name
,
layout_mapping
[
name
]))
sub_map
=
{}
for
i
in
layout_mapping
:
sub_map
[
'R
\\
.layout
\\
.'
+
i
+
'(
\\
W)'
]
=
'R.layout.'
+
layout_mapping
[
i
]
+
'
\\
g<1>'
# ViewBinding 同步修改
sub_map
[
get_title
(
i
,
True
)
+
'Binding'
]
=
get_title
(
layout_mapping
[
i
],
True
)
+
'Binding'
sub_map
[
'(>|")@layout/'
+
i
+
'(<|")'
]
=
'
\\
g<1>@layout/'
+
layout_mapping
[
i
]
+
'
\\
g<2>'
sub_map_text
(
sub_map
)
# 改 drawable 文件名
deal_res_type
(
'drawable'
)
# 改 mipmap 文件名
deal_res_type
(
'mipmap'
)
# 改 raw 文件名
deal_res_type
(
'raw'
)
# 改 raw 文件名
deal_res_type
(
'xml'
)
# 改图片内容
deal_image
()
def
check_activity_mapping
():
try
:
loads
=
json
.
load
(
open
(
'mapping.json'
,
'r'
,
encoding
=
'utf-8'
))
except
(
ValueError
,
IOError
):
loads
=
{}
old_list
=
loads
.
get
(
'activity'
,
[])
old_paths
=
[]
for
i
in
old_list
:
old_paths
.
append
(
i
[:
i
.
rfind
(
'.'
)])
old_paths
=
sorted
(
set
(
old_paths
),
key
=
old_paths
.
index
)
old_paths
.
sort
(
key
=
len
)
classes
=
get_classes
()
paths
=
[]
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
for
i
in
classes
:
paths
.
append
(
i
[
len
(
root_path
)
+
1
:
i
.
rfind
(
os
.
sep
)]
.
replace
(
os
.
sep
,
'.'
))
paths
=
sorted
(
set
(
paths
),
key
=
paths
.
index
)
paths
.
sort
(
key
=
len
)
new_list
=
[]
for
i
in
old_list
:
if
i
[:
i
.
rfind
(
'.'
)]
in
paths
:
new_list
.
append
(
i
)
for
i
in
paths
:
if
i
in
old_paths
:
continue
# 每个路径下产生随机个垃圾类
for
_
in
range
(
random
.
randint
(
0
,
3
)):
name
=
get_title
(
get_random_string
(
4
),
True
)
+
'_D'
new_list
.
append
(
i
+
'.'
+
name
)
loads
[
"activity"
]
=
new_list
json
.
dump
(
loads
,
open
(
'mapping.json'
,
'w'
,
encoding
=
'utf-8'
),
indent
=
4
)
return
new_list
def
add_junk_activity
():
root_path
=
get_path
(
'.
\\
src
\\
main
\\
java'
)
new_list
=
check_activity_mapping
()
count
=
len
(
new_list
)
random
.
shuffle
(
new_list
)
for
i
in
range
(
count
):
class_path
=
get_path
(
root_path
+
'
\\
'
+
new_list
[
i
]
.
replace
(
'.'
,
'
\\
'
)
+
'.kt'
)
# 获取垃圾类代码
code
=
get_random_activity_code
(
new_list
[
i
],
new_list
[(
i
+
1
)
%
count
])
with
open
(
class_path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
code
)
print
(
class_path
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
replace_string
=
'
\n
'
for
i
in
new_list
:
replace_string
+=
' <activity android:name="'
+
i
+
'" />
\n
'
text
=
text
.
replace
(
' </application>'
,
replace_string
+
''' </application>'''
)
with
open
(
get_path
(
'.
\\
src
\\
main
\\
AndroidManifest.xml'
),
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
get_random_view
():
return
random
.
choice
(
[
'TextView'
,
'Button'
,
'EditText'
,
'ImageView'
,
'FrameLayout'
,
'LinearLayout'
,
'CalendarView'
,
'CheckBox'
,
'CheckedTextView'
,
'DatePicker'
,
'ExpandableListView'
,
'GridLayout'
,
'GridView'
,
'HorizontalScrollView'
,
'ImageButton'
,
'ListView'
,
'RelativeLayout'
,
'ScrollView'
,
'SearchView'
,
'SeekBar'
,
'TableLayout'
])
def
get_random_activity_code
(
class1
,
class2
):
# 代码中,class1 跳转 class2,确保垃圾类被引用到
package1
=
class1
[:
class1
.
rfind
(
'.'
)]
name1
=
class1
[
len
(
package1
)
+
1
:]
package2
=
class2
[:
class2
.
rfind
(
'.'
)]
name2
=
class2
[
len
(
package2
)
+
1
:]
view
=
get_random_view
()
if
package1
==
package2
:
import_code
=
''
else
:
import_code
=
'
\n
import '
+
class2
code
=
'''package '''
+
package1
+
'''
import android.content.Intent
import android.os.Bundle
import android.widget.'''
+
view
+
'''
import androidx.appcompat.app.AppCompatActivity'''
+
import_code
+
'''
class '''
+
name1
+
''' : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView('''
+
view
+
'''(this))
startActivity(Intent(this, '''
+
name2
+
'''::class.java))
}
}'''
return
code
def
add_junk_method
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
result_text
=
text
interfaces
=
re
.
findall
(
'interface .*?{.*?}'
,
text
,
flags
=
re
.
S
)
for
interface
in
interfaces
:
start
=
text
.
find
(
interface
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
# 过滤接口及其内容
text
=
text
.
replace
(
text
[
start
:
index
],
''
)
functions
=
re
.
findall
(
'fun (?!interface ).*?
\\
(.*?
\\
)'
,
text
,
flags
=
re
.
S
)
for
function
in
functions
:
start
=
text
.
find
(
function
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'('
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
')'
:
count
-=
1
index
+=
1
if
'abstract'
in
text
[
start
:
index
]:
continue
count
=
0
isStart
=
False
param_end
=
index
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
not
isStart
and
text
[
index
]
==
'='
:
break
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
param_end
=
index
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
if
not
isStart
:
continue
fun_text
=
text
[
start
:
index
]
header
=
text
[
start
:
param_end
]
param_start
=
start
+
header
.
find
(
'('
)
context
=
re
.
search
(
'fun (.*?
\\
.)?
\\
w*?'
,
text
[
start
:
param_start
])[
1
]
if
context
is
None
:
context
=
''
param_string
=
text
[
param_start
:
param_end
]
if
'override fun '
in
header
and
'
\n
'
+
\
re
.
sub
(
'(final )?override fun '
,
'super.'
,
header
[:
header
.
index
(
param_string
)])
in
fun_text
:
methods
=
[]
for
i
in
range
(
random
.
randint
(
0
,
5
)):
result
=
add_one_method
(
fun_text
,
param_string
,
header
,
context
)
if
result
is
None
or
len
(
result
)
!=
3
:
continue
fun_text
,
method_text1
,
method_text2
=
result
methods
.
insert
(
0
,
method_text2
)
methods
.
insert
(
0
,
method_text1
)
methods
.
insert
(
0
,
fun_text
)
fun_text
=
'
\n\n
'
.
join
(
methods
)
else
:
methods
=
[]
for
i
in
range
(
random
.
randint
(
0
,
5
)):
result
=
add_one_method
(
fun_text
,
param_string
,
header
,
context
)
if
result
is
None
or
len
(
result
)
!=
2
:
continue
fun_text
,
method_text
=
result
methods
.
insert
(
0
,
method_text
)
methods
.
insert
(
0
,
fun_text
)
fun_text
=
'
\n\n
'
.
join
(
methods
)
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
fun_text
)
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
def
add_one_method
(
fun_text
,
param_string
,
header
,
context
):
if
'suspend '
in
header
:
suspend
=
'suspend '
else
:
suspend
=
''
body
=
fun_text
[
len
(
header
):]
intent
=
len
(
fun_text
)
-
len
(
fun_text
.
lstrip
())
param
=
param_string
[
1
:
param_string
.
rfind
(
')'
)]
param
=
re
.
sub
(
'<.*?>'
,
''
,
param
)
param
=
re
.
sub
(
'
\\
([^(]*?
\\
)'
,
'()'
,
param
)
param
=
[
i
.
strip
()
.
split
(
':'
)[
0
]
for
i
in
param
.
split
(
','
)]
for
i
in
range
(
len
(
param
)):
if
param
[
i
]
.
startswith
(
'vararg'
):
param
[
i
]
=
'*'
+
param
[
i
]
.
split
(
' '
)[
-
1
]
elif
param
[
i
]
.
startswith
(
'@'
):
param
[
i
]
=
param
[
i
]
.
split
(
' '
)[
-
1
]
if
'override fun '
in
header
and
'
\n
'
+
\
re
.
sub
(
'(final )?override fun '
,
'super.'
,
header
[:
header
.
index
(
param_string
)])
in
fun_text
:
if
':'
in
param_string
[
param_string
.
rfind
(
')'
):]:
return
method_split
=
[
i
.
rstrip
()
for
i
in
fun_text
.
split
(
'
\n
'
)]
if
method_split
[
0
]
.
rstrip
()[
-
1
]
!=
'{'
or
method_split
[
-
1
]
.
lstrip
()[
0
]
!=
'}'
:
return
method_body
=
method_split
[
1
:
-
1
]
super_index
=
-
1
for
i
in
range
(
len
(
method_body
)):
if
'super.'
in
method_body
[
i
]:
if
super_index
>=
0
:
super_index
=
-
1
break
super_index
=
i
if
super_index
<
0
:
return
method_text1
=
method_split
.
copy
()
method_name1
=
get_random_string
(
is_ascii
=
False
)
method_text1
[
0
]
=
method_text1
[
0
]
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name1
+
param_string
)
method_text1
[
1
:
-
1
]
=
method_body
[:
super_index
]
method_text2
=
method_split
.
copy
()
method_name2
=
get_random_string
(
is_ascii
=
False
)
method_text2
[
0
]
=
method_text2
[
0
]
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name2
+
param_string
)
method_text2
[
1
:
-
1
]
=
method_body
[
super_index
+
1
:]
method_body
[
super_index
+
1
:]
=
[
' '
*
(
intent
+
4
)
+
method_name2
+
'('
+
', '
.
join
(
param
)
+
')'
]
method_body
[:
super_index
]
=
[
' '
*
(
intent
+
4
)
+
method_name1
+
'('
+
', '
.
join
(
param
)
+
')'
]
method_split
[
1
:
-
1
]
=
method_body
method_text1
=
'
\n
'
.
join
(
method_text1
)
method_text2
=
'
\n
'
.
join
(
method_text2
)
fun_text
=
'
\n
'
.
join
(
method_split
)
return
fun_text
,
method_text1
,
method_text2
else
:
method_name
=
get_random_string
(
is_ascii
=
False
)
method_text
=
fun_text
if
':'
in
param_string
[
param_string
.
rfind
(
')'
):]:
method_text
=
method_text
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name
+
param_string
)
fun_text
=
fun_text
.
replace
(
body
,
'{
\n
'
+
' '
*
(
intent
+
4
)
+
'return '
+
method_name
+
'('
+
', '
.
join
(
param
)
+
')
\n
'
+
' '
*
intent
+
'}'
)
else
:
method_text
=
method_text
.
replace
(
header
,
' '
*
intent
+
'private '
+
suspend
+
'fun '
+
context
+
method_name
+
param_string
)
fun_text
=
fun_text
.
replace
(
body
,
'{
\n
'
+
' '
*
(
intent
+
4
)
+
method_name
+
'('
+
', '
.
join
(
param
)
+
')
\n
'
+
' '
*
intent
+
'}'
)
return
fun_text
,
method_text
def
add_junk_code
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
functions
=
re
.
findall
(
'((?=fun .*?
\\
([^}]*?
\\
)|init |val.*?by lazy)[^}]*?
\\
{)'
,
text
)
result_text
=
text
for
function
in
functions
:
start
=
text
.
find
(
function
)
start
=
text
[:
start
]
.
rfind
(
'
\n
'
)
+
1
if
start
==
-
1
:
continue
index
=
start
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'('
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
')'
:
count
-=
1
if
not
isStart
and
text
[
index
]
==
'{'
:
break
index
+=
1
count
=
0
isStart
=
False
while
(
not
isStart
or
count
>
0
)
and
index
<
len
(
text
):
if
text
[
index
]
==
'{'
:
count
+=
1
if
count
==
1
:
isStart
=
True
elif
text
[
index
]
==
'}'
:
count
-=
1
index
+=
1
fun_text
=
text
[
start
:
index
]
fun_text
=
fun_text
.
split
(
'
\n
'
)
intent_stack
=
[]
last_intent
=
0
log_indexes
=
[]
skip_text
=
[
False
for
_
in
fun_text
]
i
=
0
while
i
<
len
(
fun_text
):
if
'object : '
in
fun_text
[
i
]
and
fun_text
[
i
]
.
rstrip
()
.
endswith
(
'{'
):
intent
=
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
while
i
<
len
(
fun_text
)
-
1
:
i
+=
1
skip_text
[
i
]
=
True
if
fun_text
[
i
]
.
lstrip
()
.
startswith
(
'}'
)
and
\
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
==
intent
:
break
i
+=
1
for
i
in
range
(
len
(
fun_text
)):
if
skip_text
[
i
]:
continue
intent
=
len
(
fun_text
[
i
])
-
len
(
fun_text
[
i
]
.
lstrip
())
if
intent
==
0
or
intent
%
4
!=
0
:
continue
if
intent
>
last_intent
and
i
>
0
:
j
=
i
-
1
while
len
(
fun_text
[
j
])
-
len
(
fun_text
[
j
]
.
lstrip
())
==
0
and
j
>=
0
:
j
-=
1
if
j
>=
0
:
for
k
in
range
(
int
((
intent
-
last_intent
)
/
4
)):
intent_stack
.
append
(
j
)
elif
intent
<
last_intent
:
for
k
in
range
(
int
((
last_intent
-
intent
)
/
4
)):
intent_stack
.
pop
()
if
len
(
intent_stack
)
>
0
and
intent
>=
last_intent
\
and
len
(
fun_text
[
i
]
.
strip
())
!=
0
and
fun_text
[
i
]
.
lstrip
()[
0
]
!=
')'
:
last_text
=
fun_text
[
intent_stack
[
-
1
]]
if
last_text
[
-
1
]
!=
'{'
:
continue
if
last_text
.
lstrip
()[
0
]
==
')'
:
last_text_intent
=
len
(
last_text
)
-
len
(
last_text
.
lstrip
())
j
=
intent_stack
[
-
1
]
-
1
while
j
>=
0
:
temp_text
=
fun_text
[
j
]
if
len
(
temp_text
)
-
len
(
temp_text
.
lstrip
())
==
last_text_intent
:
break
j
-=
1
if
j
>=
0
:
last_text
=
fun_text
[
j
]
+
last_text
.
strip
()
if
'when'
not
in
last_text
and
'$'
not
in
last_text
and
\
'object'
not
in
last_text
and
'class '
not
in
last_text
and
'interface '
not
in
last_text
:
log_indexes
.
append
((
i
,
intent
))
last_intent
=
intent
log_indexes
.
reverse
()
for
i
in
log_indexes
:
if
random
.
random
()
>
0.35
:
continue
junk_code
=
get_random_junk_code
()
junk_code
=
junk_code
.
replace
(
'
\n
'
,
'
\n
'
+
' '
*
i
[
1
])[
1
:]
fun_text
.
insert
(
i
[
0
],
junk_code
)
result_text
=
result_text
.
replace
(
text
[
start
:
index
],
'
\n
'
.
join
(
fun_text
))
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
result_text
)
add_import
(
'android.util.Log'
,
classes
)
def
get_random_junk_code
():
junk_code
=
random
.
choice
(
junk_codes
)
count
=
1
while
True
:
random_str
=
get_random_string
(
is_ascii
=
False
)
replace
=
junk_code
.
replace
(
'[str'
+
str
(
count
)
+
']'
,
random_str
)
if
junk_code
==
replace
:
break
junk_code
=
replace
count
+=
1
count
=
1
while
True
:
random_int
=
get_random_int
()
replace
=
junk_code
.
replace
(
'[int'
+
str
(
count
)
+
']'
,
str
(
random_int
))
if
junk_code
==
replace
:
break
junk_code
=
replace
count
+=
1
return
junk_code
junk_codes
=
[
'''
if (System.currentTimeMillis() < [int1]) {
println(System.currentTimeMillis())
}'''
,
'''
Log.d("[str1]", "[str1]")'''
,
'''
val [str1] = [int1]..[int1] + 10
println([str1].random())'''
,
'''
val [str1]: (Int, Int) -> Int = { [str2], [str3] -> [str2] + [str3] }
println([str1].invoke([int1], [int2]))'''
,
'''
class [str1](val [str2]: String, val [str3]: Int)
println([str1]("[str4]", [int1]))'''
,
'''
open class [str1] {
open fun [str2]() {}
}
class [str3] : [str1]() {
override fun [str2]() {
println("[str5]")
}
}
val [str4] = [str3]()
println([str4])'''
,
'''
fun String.[str1](): Boolean {
return this == this.reversed()
}
val [str2] = "[str4]"
val [str3] = [str2].[str1]()
println([str3])'''
,
'''
fun [str1]([str2]: Int, [str3]: Int): Int {
return [str2] + [str3]
}
println([str1]([int1], [int2]))'''
,
'''
val [str1] = { [str2]: String -> println([str2]) }
[str1]("[str3]!")'''
,
'''
fun [str1]([str2]: String) {
println("tag, $[str2]!")
}
[str1]("[str3]")'''
,
'''
fun [str1]() {
fun [str2]([str3]: Int) {
println([str3])
}
[str2]([int1])
[str2]([int2])
[str2]([int3])
}
[str1]()'''
,
'''
class [str1] {
inner class [str2] {
fun [str3]() {
println("[str5]")
}
}
}
val [str4] = [str1]().[str2]()
[str4].[str3]()'''
,
'''
class [str1] {
fun [str2]() {
println("[str3]")
}
}
[str1]().[str2]()'''
,
'''
abstract class [str1] {
abstract fun [str2]()
}
class [str3] : [str1]() {
override fun [str2]() {
println("[str5]")
}
}
val [str4] = [str3]()
[str4].[str2]()'''
,
'''
class [str1]<T>(val [str2]: T)
val [str3] = [str1]([int1])
val [str4] = [str1]("[str5]")
println([str3])
println([str4])'''
,
'''
fun <T> [str1]([str2]: T) {
println([str2])
}
[str1]([int1])
[str1]("[str3]")'''
,
'''
class [str1]<T, K>(val [str3]: T, val [str4]: K) {
init {
println("[str5]")
}
}
val [str2] = [str1]("[str6]", [int1])
println([str2])'''
,
'''
class [str1]<T>(val [str2]: T, val [str3]: Int) {
constructor([str4]: T) : this([str4], [int1]) {
println("[str5]")
}
}
println([str1]("[str6]"))'''
,
'''
val [str1] = [int1]
val [str2] = [int2]
val [str3] = [str1] * [str2] * [str2]
println([str3])'''
,
'''
fun [str1]([str3]: Int, [str4]: Int): Int {
return [str3] + [str4]
}
val [str2] = [str1]([int1], [int2])
println([str2])'''
,
'''
fun [str1]([str4]: Int, [str5]: Int): Int {
fun [str2]([str6]: Int, [str7]: Int): Int {
return [str6] + [str7]
}
return [str2]([str4], [str5])
}
val [str3] = [str1]([int1], [int2])
println([str3])'''
,
'''
class [str1] {
val [str2] by lazy {
println("[str4]")
"[str5]!"
}
}
val [str3] = [str1]()
println([str3].[str2])'''
,
'''
class [str1]<T>([str3]: T) {
init {
println("[str4]: $[str3]")
}
}
println([str1]("[str2]"))'''
,
'''
class [str1]<T>(val [str3]: T, val [str4]: Int) {
constructor([str3]: T) : this([str3], [int1]) {
println("[str4]")
}
}
println([str1]("[str2]"))'''
,
'''
class [str1]<T>(val [str4]: T)
val [str2] = [str1]([int1])
val [str3] = [str1]("[str5]")
println([str2].[str4])
println([str3].[str4])'''
]
def
class_disorder
():
classes
=
get_classes
([
'kt'
])
for
path
in
classes
:
with
open
(
path
,
'r'
,
encoding
=
'utf-8'
)
as
f
:
text
=
f
.
read
()
if
text
.
find
(
'data class'
)
!=
-
1
:
continue
text
=
re
.
sub
(
'@SuppressLint.*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'//[^"]*?(("[^"]*?){2})*?
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
' +
\n
'
,
'
\n
'
,
text
)
text
=
re
.
sub
(
'=
\\
s+'
,
'= '
,
text
)
text
=
re
.
sub
(
':
\\
s+'
,
': '
,
text
)
text
=
re
.
sub
(
',
\\
s+'
,
', '
,
text
)
text
=
re
.
sub
(
'/
\\
*[
\\
s
\\
S]*?
\\
*/'
,
''
,
text
)
text
=
re
.
sub
(
'
\n
{2,}'
,
'
\n\n
'
,
text
)
lines
=
text
.
split
(
'
\n
'
)
count
=
0
begin
=
0
result
=
[]
start
=
-
1
end
=
0
for
index
in
range
(
len
(
lines
)):
if
len
(
lines
[
index
]
.
strip
())
==
0
:
continue
if
start
==
-
1
:
if
lines
[
index
][
-
1
]
==
'{'
:
start
=
index
count
+=
1
continue
for
char
in
lines
[
index
]:
if
char
in
[
'{'
,
'('
]:
count
+=
1
elif
char
in
[
'}'
,
')'
]:
if
count
==
1
:
end
=
index
count
-=
1
if
count
==
1
:
if
lines
[
index
][
-
1
]
in
[
'}'
,
')'
]
and
begin
!=
0
:
if
'get()'
in
lines
[
begin
]
or
'set(value)'
in
lines
[
begin
]:
for
i
in
range
(
len
(
result
)):
if
result
[
i
][
1
]
==
begin
:
result
[
i
]
=
(
result
[
i
][
0
],
index
+
1
)
break
else
:
result
.
append
((
begin
,
index
+
1
))
begin
=
0
elif
lines
[
index
][
-
1
]
not
in
[
'{'
,
'('
]:
strip
=
lines
[
index
]
.
lstrip
()
if
strip
[
0
]
==
'.'
or
strip
.
startswith
(
'get() ='
)
or
strip
.
startswith
(
'set(value) = '
):
for
i
in
range
(
len
(
result
)):
if
result
[
i
][
1
]
==
index
:
result
[
i
]
=
(
result
[
i
][
0
],
index
+
1
)
break
else
:
result
.
append
((
index
,
index
+
1
))
elif
count
==
2
and
(
lines
[
index
][
-
1
]
in
[
'{'
,
'('
]
or
lines
[
index
]
.
endswith
(
'->'
))
\
and
lines
[
begin
][
-
1
]
not
in
[
'{'
,
'('
]:
begin
=
index
result_temp
=
[]
i
=
0
while
i
<
len
(
result
):
begin
=
result
[
i
][
0
]
while
lines
[
result
[
i
][
0
]]
.
lstrip
()
.
startswith
(
'@'
):
i
+=
1
result_temp
.
append
([
begin
,
result
[
i
][
1
]])
i
+=
1
result
=
result_temp
random
.
shuffle
(
result
)
result_sort
=
result
.
copy
()
var_weight
=
{}
for
i
in
re
.
findall
(
'va[lr] (
\\
w+)'
,
text
):
var_weight
[
i
]
=
len
(
re
.
findall
(
'
\\
W'
+
re
.
escape
(
i
)
+
'
\\
W'
,
text
))
for
var
in
sorted
(
var_weight
,
key
=
lambda
k
:
var_weight
[
k
]):
for
i
in
range
(
len
(
result
)):
findall
=
re
.
findall
(
'va[lr] ('
+
re
.
escape
(
var
)
+
')'
,
lines
[
result
[
i
][
0
]])
if
len
(
findall
)
==
0
:
continue
result_sort
.
remove
(
result
[
i
])
result_sort
.
insert
(
0
,
result
[
i
])
break
result
=
result_sort
text
=
'
\n
'
.
join
(
lines
[:
start
+
1
])
+
'
\n
'
for
i
in
result
:
text
+=
'
\n
'
+
'
\n
'
.
join
(
lines
[
i
[
0
]:
i
[
1
]])
+
'
\n
'
text
+=
'
\n
'
.
join
(
lines
[
end
:])
with
open
(
path
,
'w'
,
encoding
=
'utf-8'
)
as
f
:
f
.
write
(
text
)
def
deal_junk
():
# 添加垃圾类
add_junk_activity
()
# 添加方法嵌套
add_junk_method
()
# 添加垃圾代码
add_junk_code
()
# 类成员乱序
class_disorder
()
def
get_path
(
path
):
paths
=
path
.
split
(
'
\\
'
)
return
str
(
os
.
path
.
join
(
*
paths
))
def
main
():
if
not
os
.
path
.
exists
(
get_path
(
'.
\\
src
\\
main
\\
java
\\
'
+
applicationId
[:
applicationId
.
find
(
'.'
)])):
return
# 资源混淆
deal_res
()
# 垃圾代码
deal_junk
()
# 代码处理
deal_code
()
if
__name__
==
'__main__'
:
if
os
.
path
.
exists
(
'build.gradle'
):
gradle_path
=
'build.gradle'
elif
os
.
path
.
exists
(
'build.gradle.kts'
):
gradle_path
=
'build.gradle.kts'
else
:
exit
(
'找不到 build.gradle 文件'
)
applicationId
=
re
.
search
(
'applicationId .*?["
\'
](.*?)["
\'
]'
,
open
(
gradle_path
,
'r'
,
encoding
=
'utf-8'
)
.
read
())[
1
]
aesKey
=
find_text
(
' aesKey ?= ?"(.*?)"'
,
get_path
(
'.
\\
src
\\
main
\\
java'
))[
0
]
print
(
'包名: '
+
applicationId
,
'aesKey: '
+
aesKey
)
if
find_text
(
'release ?{
\\
s*?(?:isM|m)inifyEnabled(?: ?= ?| )true'
,
is_one
=
True
)
is
None
:
exit
(
'官方混淆未开启'
)
if
find_text
(
'
\\
s*?ndk ?{'
,
is_one
=
True
)
is
None
:
exit
(
'ndk未配置'
)
main
()
app/src/androidTest/java/com/base/s
mart
filemanager/ExampleInstrumentedTest.kt
→
app/src/androidTest/java/com/base/s
uper
filemanager/ExampleInstrumentedTest.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager
package
com.base.s
uper
filemanager
import
androidx.test.platform.app.InstrumentationRegistry
import
androidx.test.ext.junit.runners.AndroidJUnit4
...
...
app/src/main/AndroidManifest.xml
View file @
4a0909ac
...
...
@@ -44,6 +44,10 @@
android:screenOrientation=
"portrait"
tools:ignore=
"DiscouragedApi,LockedOrientationActivity"
/>
<meta-data
android:name=
"com.facebook.sdk.ApplicationId"
android:value=
"@string/facebook_app_id"
/>
</application>
</manifest>
\ No newline at end of file
app/src/main/java/com/base/s
mart
filemanager/BaseApplication.kt
→
app/src/main/java/com/base/s
uper
filemanager/BaseApplication.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager
package
com.base.s
uper
filemanager
import
android.app.Application
...
...
app/src/main/java/com/base/s
mart
filemanager/MyApplication.kt
→
app/src/main/java/com/base/s
uper
filemanager/MyApplication.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager
package
com.base.s
uper
filemanager
class
MyApplication
:
BaseApplication
()
{
override
fun
init
()
{
...
...
app/src/main/java/com/base/s
mart
filemanager/activity/FileCategoryActivity.kt
→
app/src/main/java/com/base/s
uper
filemanager/activity/FileCategoryActivity.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.activity
package
com.base.s
uper
filemanager.activity
import
android.os.Bundle
import
android.view.View
import
android.widget.LinearLayout
import
androidx.activity.enableEdgeToEdge
import
androidx.appcompat.app.AppCompatActivity
import
androidx.core.view.ViewCompat
import
androidx.core.view.WindowInsetsCompat
import
androidx.lifecycle.lifecycleScope
import
androidx.recyclerview.widget.DividerItemDecoration
import
com.base.smartfilemanager.R
import
com.base.smartfilemanager.adapter.FileBrowseAdapter
import
com.base.smartfilemanager.bean.FileBean
import
com.base.smartfilemanager.bean.FileCategoryBean
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.APK
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.Audio
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.DOC
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.Image
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.PDF
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.PPT
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.TXT
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.Video
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.XLS
import
com.base.smartfilemanager.bean.FileCategoryBean.Companion.ZIP
import
com.base.smartfilemanager.databinding.ActivityFileCategoryBinding
import
com.base.smartfilemanager.helps.BaseActivity
import
com.base.smartfilemanager.helps.file.FileEx.deleteDirectory
import
com.base.smartfilemanager.helps.file.FileHelps
import
com.base.smartfilemanager.view.FileDeleteDialog
import
com.base.smartfilemanager.view.FileDeleteDialog.showFileDeleteDialog
import
com.base.superfilemanager.adapter.FileBrowseAdapter
import
com.base.superfilemanager.bean.FileBean
import
com.base.superfilemanager.bean.FileCategoryBean
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.APK
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.Audio
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.DOC
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.Image
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.PDF
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.PPT
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.TXT
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.Video
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.XLS
import
com.base.superfilemanager.bean.FileCategoryBean.Companion.ZIP
import
com.base.superfilemanager.databinding.ActivityFileCategoryBinding
import
com.base.superfilemanager.helps.BaseActivity
import
com.base.superfilemanager.helps.file.FileEx.deleteDirectory
import
com.base.superfilemanager.helps.file.FileHelps
import
com.base.superfilemanager.view.FileDeleteDialog.showFileDeleteDialog
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.async
import
kotlinx.coroutines.launch
...
...
app/src/main/java/com/base/s
mart
filemanager/activity/MainActivity.kt
→
app/src/main/java/com/base/s
uper
filemanager/activity/MainActivity.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.activity
package
com.base.s
uper
filemanager.activity
import
android.graphics.Typeface
import
androidx.fragment.app.Fragment
import
androidx.viewpager2.adapter.FragmentStateAdapter
import
androidx.viewpager2.widget.ViewPager2
import
com.base.s
mart
filemanager.fragment.FileCategoryFragment
import
com.base.s
mart
filemanager.databinding.ActivityMainBinding
import
com.base.s
mart
filemanager.helps.BaseActivity
import
com.base.s
uper
filemanager.fragment.FileCategoryFragment
import
com.base.s
uper
filemanager.databinding.ActivityMainBinding
import
com.base.s
uper
filemanager.helps.BaseActivity
class
MainActivity
:
BaseActivity
<
ActivityMainBinding
>()
{
...
...
app/src/main/java/com/base/superfilemanager/activity/PrivacyWebActivity.kt
0 → 100644
View file @
4a0909ac
package
com.base.superfilemanager.activity
import
android.annotation.SuppressLint
import
android.graphics.Color
import
android.webkit.WebView
import
android.webkit.WebViewClient
import
androidx.core.view.updatePadding
import
com.base.superfilemanager.databinding.ActivityLayoutWebPrivacyBinding
import
com.base.superfilemanager.helps.BaseActivity
import
com.blankj.utilcode.util.BarUtils
class
PrivacyWebActivity
:
BaseActivity
<
ActivityLayoutWebPrivacyBinding
>()
{
override
val
binding
:
ActivityLayoutWebPrivacyBinding
by
lazy
{
ActivityLayoutWebPrivacyBinding
.
inflate
(
layoutInflater
)
}
@SuppressLint
(
"SetJavaScriptEnabled"
)
override
fun
initView
()
{
BarUtils
.
setStatusBarLightMode
(
this
,
true
)
BarUtils
.
setStatusBarColor
(
this
,
Color
.
TRANSPARENT
)
binding
.
root
.
updatePadding
(
top
=
BarUtils
.
getStatusBarHeight
())
binding
.
idWeb
.
settings
.
setJavaScriptEnabled
(
true
)
binding
.
idWeb
.
webViewClient
=
object
:
WebViewClient
()
{
override
fun
shouldOverrideUrlLoading
(
view
:
WebView
?,
url
:
String
?):
Boolean
{
view
?.
loadUrl
(
url
!!
)
return
true
}
}
binding
.
idWeb
.
loadUrl
(
""
)
binding
.
idBack
.
setOnClickListener
{
finishToMain
()
}
}
}
\ No newline at end of file
app/src/main/java/com/base/superfilemanager/activity/splash/PrivacyAgreementManager.kt
0 → 100644
View file @
4a0909ac
package
com.base.superfilemanager.activity.splash
import
android.app.Activity
import
android.content.Intent
import
android.net.Uri
import
android.text.SpannableString
import
android.text.Spanned
import
android.text.style.UnderlineSpan
import
androidx.core.view.isVisible
import
com.base.superfilemanager.databinding.ActivitySplashBinding
import
com.base.superfilemanager.helps.ConfigHelper
class
PrivacyAgreementManager
{
private
val
binding
:
ActivitySplashBinding
private
val
context
:
Activity
private
val
listener
:
onUserPrivacyAggreementListener
constructor
(
binding
:
ActivitySplashBinding
,
context
:
Activity
,
listener
:
onUserPrivacyAggreementListener
)
{
this
.
binding
=
binding
this
.
context
=
context
this
.
listener
=
listener
initView
()
}
private
fun
initView
()
{
val
spannableString
=
SpannableString
(
"Privacy Policy"
)
spannableString
.
setSpan
(
UnderlineSpan
(),
0
,
spannableString
.
length
,
Spanned
.
SPAN_EXCLUSIVE_EXCLUSIVE
)
binding
.
idTvPrivacyPolicy
.
text
=
spannableString
binding
.
idTvPrivacyPolicy
.
setOnClickListener
{
val
intent
=
Intent
(
Intent
.
ACTION_VIEW
,
Uri
.
parse
(
"https://sites.google.com/view/esuper-file-manager/home"
)
)
context
.
startActivity
(
intent
)
}
binding
.
idTvStart
.
setOnClickListener
{
binding
.
idTvStart
.
isVisible
=
false
binding
.
idLlJindu
.
isVisible
=
true
binding
.
idLlYinsi
.
isVisible
=
false
ConfigHelper
.
ifAgreePrivacy
=
true
// EventHelper.event("click_start_to_use")
// EventHelper.event("page_${javaClass.simpleName}")
listener
.
onAgreePrivacy
()
}
}
interface
onUserPrivacyAggreementListener
{
fun
onAgreePrivacy
()
}
}
\ No newline at end of file
app/src/main/java/com/base/s
mart
filemanager/activity/splash/ProgressManager.kt
→
app/src/main/java/com/base/s
uper
filemanager/activity/splash/ProgressManager.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.activity.splash
package
com.base.s
uper
filemanager.activity.splash
import
android.os.Handler
import
com.base.s
mart
filemanager.databinding.ActivitySplashBinding
import
com.base.s
uper
filemanager.databinding.ActivitySplashBinding
import
com.blankj.utilcode.util.SPUtils
class
ProgressManager
{
...
...
app/src/main/java/com/base/s
mart
filemanager/activity/splash/SplashActivity.kt
→
app/src/main/java/com/base/s
uper
filemanager/activity/splash/SplashActivity.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.activity.splash
package
com.base.s
uper
filemanager.activity.splash
import
android.Manifest
import
android.annotation.SuppressLint
import
android.content.Intent
import
android.graphics.Color
import
android.os.Build
import
android.os.Bundle
import
android.os.Handler
import
androidx.activity.enableEdgeToEdge
import
androidx.activity.result.contract.ActivityResultContracts
import
androidx.appcompat.app.AppCompatActivity
import
androidx.core.view.ViewCompat
import
androidx.core.view.WindowInsetsCompat
import
com.base.smartfilemanager.R
import
com.base.smartfilemanager.activity.MainActivity
import
com.base.smartfilemanager.databinding.ActivitySplashBinding
import
com.base.smartfilemanager.helps.BaseActivity
import
androidx.core.view.isVisible
import
com.base.superfilemanager.activity.MainActivity
import
com.base.superfilemanager.databinding.ActivitySplashBinding
import
com.base.superfilemanager.helps.BaseActivity
import
com.base.superfilemanager.helps.ConfigHelper
import
com.blankj.utilcode.util.BarUtils
@SuppressLint
(
"CustomSplashScreen"
)
class
SplashActivity
:
BaseActivity
<
ActivitySplashBinding
>(),
ProgressManager
.
ProgressListener
{
class
SplashActivity
:
BaseActivity
<
ActivitySplashBinding
>(),
ProgressManager
.
ProgressListener
,
PrivacyAgreementManager
.
onUserPrivacyAggreementListener
{
override
val
binding
:
ActivitySplashBinding
by
lazy
{
ActivitySplashBinding
.
inflate
(
layoutInflater
)
...
...
@@ -43,7 +40,14 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(), ProgressManager.Pr
return
}
mProgressManager
=
ProgressManager
(
binding
,
this
)
mProgressManager
?.
startProgress
()
if
(
ConfigHelper
.
ifAgreePrivacy
)
{
binding
.
idTvStart
.
isVisible
=
false
binding
.
idLlJindu
.
isVisible
=
true
binding
.
idLlYinsi
.
isVisible
=
false
onAgreePrivacy
()
}
else
{
PrivacyAgreementManager
(
binding
,
this
,
this
)
}
}
override
fun
onProgressMax
()
{
...
...
@@ -54,4 +58,9 @@ class SplashActivity : BaseActivity<ActivitySplashBinding>(), ProgressManager.Pr
}
override
fun
onAgreePrivacy
()
{
mProgressManager
?.
startProgress
()
}
}
\ No newline at end of file
app/src/main/java/com/base/s
mart
filemanager/adapter/FileBrowseAdapter.kt
→
app/src/main/java/com/base/s
uper
filemanager/adapter/FileBrowseAdapter.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.adapter
package
com.base.s
uper
filemanager.adapter
import
android.annotation.SuppressLint
import
android.content.Context
...
...
@@ -7,10 +7,10 @@ import android.view.ViewGroup
import
android.widget.ImageView
import
androidx.recyclerview.widget.RecyclerView
import
androidx.recyclerview.widget.RecyclerView.ViewHolder
import
com.base.s
mart
filemanager.R
import
com.base.s
mart
filemanager.bean.FileBean
import
com.base.s
mart
filemanager.databinding.ItemFileListBinding
import
com.base.s
mart
filemanager.view.XmlEx.inflate
import
com.base.s
uper
filemanager.R
import
com.base.s
uper
filemanager.bean.FileBean
import
com.base.s
uper
filemanager.databinding.ItemFileListBinding
import
com.base.s
uper
filemanager.view.XmlEx.inflate
import
com.bumptech.glide.Glide
class
FileBrowseAdapter
(
private
val
select
:
(
size
:
Int
)
->
Unit
)
:
RecyclerView
.
Adapter
<
FileBrowseAdapter
.
FB
>()
{
...
...
app/src/main/java/com/base/s
mart
filemanager/adapter/FileCategoryAdapter.kt
→
app/src/main/java/com/base/s
uper
filemanager/adapter/FileCategoryAdapter.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.adapter
package
com.base.s
uper
filemanager.adapter
import
android.annotation.SuppressLint
import
android.view.View
import
android.view.ViewGroup
import
androidx.recyclerview.widget.RecyclerView
import
androidx.recyclerview.widget.RecyclerView.ViewHolder
import
com.base.s
mart
filemanager.R
import
com.base.s
mart
filemanager.bean.FileCategoryBean
import
com.base.s
mart
filemanager.databinding.ItemFileCategoryDocBinding
import
com.base.s
mart
filemanager.databinding.ItemFileCategoryMediaBinding
import
com.base.s
mart
filemanager.databinding.ItemRecentMediaBinding
import
com.base.s
mart
filemanager.view.XmlEx.inflate
import
com.base.s
uper
filemanager.R
import
com.base.s
uper
filemanager.bean.FileCategoryBean
import
com.base.s
uper
filemanager.databinding.ItemFileCategoryDocBinding
import
com.base.s
uper
filemanager.databinding.ItemFileCategoryMediaBinding
import
com.base.s
uper
filemanager.databinding.ItemRecentMediaBinding
import
com.base.s
uper
filemanager.view.XmlEx.inflate
import
com.bumptech.glide.Glide
class
FileCategoryAdapter
(
val
mode
:
String
,
val
click
:
(
key
:
String
)
->
Unit
)
:
RecyclerView
.
Adapter
<
FileCategoryAdapter
.
DC
>()
{
...
...
app/src/main/java/com/base/s
mart
filemanager/bean/FIleBean.kt
→
app/src/main/java/com/base/s
uper
filemanager/bean/FIleBean.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.bean
package
com.base.s
uper
filemanager.bean
data class
FileBean
(
var
name
:
String
=
""
,
...
...
app/src/main/java/com/base/s
mart
filemanager/bean/FileCategoryBean.kt
→
app/src/main/java/com/base/s
uper
filemanager/bean/FileCategoryBean.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.bean
package
com.base.s
uper
filemanager.bean
data class
FileCategoryBean
(
val
key
:
String
=
""
,
...
...
app/src/main/java/com/base/s
mart
filemanager/bean/ImageDataBean.kt
→
app/src/main/java/com/base/s
uper
filemanager/bean/ImageDataBean.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.bean
package
com.base.s
uper
filemanager.bean
data class
ImageDataBean
(
val
path
:
String
,
...
...
app/src/main/java/com/base/s
mart
filemanager/fragment/FileCategoryFragment.kt
→
app/src/main/java/com/base/s
uper
filemanager/fragment/FileCategoryFragment.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.fragment
package
com.base.s
uper
filemanager.fragment
import
android.content.Intent
import
android.os.Build
...
...
@@ -6,14 +6,14 @@ import android.os.Environment
import
android.view.View
import
androidx.lifecycle.lifecycleScope
import
androidx.recyclerview.widget.GridLayoutManager
import
com.base.s
mart
filemanager.R
import
com.base.s
mart
filemanager.activity.FileCategoryActivity
import
com.base.s
mart
filemanager.activity.MainActivity
import
com.base.s
mart
filemanager.adapter.FileCategoryAdapter
import
com.base.s
mart
filemanager.bean.FileCategoryBean
import
com.base.s
mart
filemanager.databinding.FragmentFileCategoryBinding
import
com.base.s
mart
filemanager.helps.BaseFragment
import
com.base.s
mart
filemanager.helps.file.MediaStoreEx
import
com.base.s
uper
filemanager.R
import
com.base.s
uper
filemanager.activity.FileCategoryActivity
import
com.base.s
uper
filemanager.activity.MainActivity
import
com.base.s
uper
filemanager.adapter.FileCategoryAdapter
import
com.base.s
uper
filemanager.bean.FileCategoryBean
import
com.base.s
uper
filemanager.databinding.FragmentFileCategoryBinding
import
com.base.s
uper
filemanager.helps.BaseFragment
import
com.base.s
uper
filemanager.helps.file.MediaStoreEx
import
com.blankj.utilcode.constant.PermissionConstants
import
com.blankj.utilcode.util.PermissionUtils
import
kotlinx.coroutines.Dispatchers
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/AESHelper.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/AESHelper.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.util.Base64
import
java.security.SecureRandom
...
...
@@ -8,7 +8,7 @@ import javax.crypto.spec.SecretKeySpec
object
AESHelper
{
private
const
val
aesKey
=
"
nbutdub5lsfdkitt
"
private
const
val
aesKey
=
"
tqdd8p5oplj9vj3y
"
private
val
cipher
by
lazy
{
Cipher
.
getInstance
(
"AES/GCM/NoPadding"
)
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/AESTextView.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/AESTextView.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.content.Context
import
android.util.AttributeSet
import
com.base.s
mart
filemanager.helps.KotlinExt.decode
import
com.base.s
uper
filemanager.helps.KotlinExt.decode
import
com.noober.background.view.BLTextView
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/BaseActivity.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/BaseActivity.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.app.AppOpsManager
import
android.app.Dialog
...
...
@@ -12,8 +12,8 @@ import android.provider.Settings
import
androidx.activity.result.contract.ActivityResultContracts
import
androidx.appcompat.app.AppCompatActivity
import
androidx.viewbinding.ViewBinding
import
com.base.s
mart
filemanager.activity.MainActivity
import
com.base.s
mart
filemanager.view.DialogViews
import
com.base.s
uper
filemanager.activity.MainActivity
import
com.base.s
uper
filemanager.view.DialogViews
import
com.blankj.utilcode.constant.PermissionConstants
import
com.blankj.utilcode.util.ActivityUtils
import
com.blankj.utilcode.util.BarUtils
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/BaseFragment.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/BaseFragment.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.os.Bundle
import
android.view.LayoutInflater
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/ConfigHelper.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/ConfigHelper.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
com.blankj.utilcode.util.AppUtils
import
com.blankj.utilcode.util.SPUtils
...
...
@@ -11,8 +11,8 @@ object ConfigHelper {
// 域名
const
val
eventUrl
=
"https://rp.
cansole764cansole
.xyz"
const
val
apiUrl
=
"https://api.
cansole764cansole
.xyz"
const
val
eventUrl
=
"https://rp.
denisjodion560
.xyz"
const
val
apiUrl
=
"https://api.
denisjodion560
.xyz"
// admob广告id
const
val
openAdmobId
=
"/6499/example/app-open"
...
...
@@ -20,7 +20,7 @@ object ConfigHelper {
const
val
nativeAdmobId
=
"ca-app-pub-3940256099942544/2247696110"
// 正式包名
const
val
packageName
=
"com.kk
.cleanmaster.file.cleanmaster.master
"
const
val
packageName
=
"com.kk
zxaakk.filemanagerr.abcd
"
val
noLoadingActivities
=
listOf
(
"full"
,
// 过滤全屏广告
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/EventHelper.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/EventHelper.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.os.Build
import
android.util.Log
import
com.base.s
mart
filemanager.helps.ConfigHelper.ifAgreePrivacy
import
com.base.s
uper
filemanager.helps.ConfigHelper.ifAgreePrivacy
import
com.blankj.utilcode.BuildConfig
import
com.blankj.utilcode.util.AppUtils
import
com.blankj.utilcode.util.DeviceUtils
...
...
@@ -39,6 +39,7 @@ object EventHelper {
ext
:
JSONObject
?
=
null
,
isSingleEvent
:
Boolean
=
false
)
{
return
if
(!
ifAgreePrivacy
)
{
Log
.
e
(
TAG
,
"ifAgreePrivacy=$ifAgreePrivacy"
)
return
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/KotlinExt.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/KotlinExt.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps
package
com.base.s
uper
filemanager.helps
import
android.view.View
import
com.base.s
mart
filemanager.BaseApplication
import
com.base.s
uper
filemanager.BaseApplication
import
org.json.JSONObject
import
java.text.SimpleDateFormat
import
java.util.Locale
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/file/FileEx.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/file/FileEx.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps.file
package
com.base.s
uper
filemanager.helps.file
import
java.io.File
import
java.util.Stack
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/file/FileHelps.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/file/FileHelps.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps.file
package
com.base.s
uper
filemanager.helps.file
import
android.os.Environment
import
android.provider.MediaStore
import
android.text.TextUtils
import
com.base.s
mart
filemanager.BaseApplication
import
com.base.s
mart
filemanager.bean.FileBean
import
com.base.s
mart
filemanager.bean.ImageDataBean
import
com.base.s
uper
filemanager.BaseApplication
import
com.base.s
uper
filemanager.bean.FileBean
import
com.base.s
uper
filemanager.bean.ImageDataBean
import
com.blankj.utilcode.util.FileUtils
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.MainScope
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/file/ImageHelper.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/file/ImageHelper.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps.file
package
com.base.s
uper
filemanager.helps.file
import
android.graphics.Bitmap
import
android.graphics.BitmapFactory
import
android.graphics.Color
import
android.media.ThumbnailUtils
import
com.base.s
mart
filemanager.bean.ImageDataBean
import
com.base.s
uper
filemanager.bean.ImageDataBean
import
com.blankj.utilcode.util.ScreenUtils
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
...
...
app/src/main/java/com/base/s
mart
filemanager/helps/file/MediaStoreEx.kt
→
app/src/main/java/com/base/s
uper
filemanager/helps/file/MediaStoreEx.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.helps.file
package
com.base.s
uper
filemanager.helps.file
import
android.content.ContentUris
import
android.content.Context
...
...
app/src/main/java/com/base/s
mart
filemanager/view/DialogViews.kt
→
app/src/main/java/com/base/s
uper
filemanager/view/DialogViews.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.view
package
com.base.s
uper
filemanager.view
import
android.app.Dialog
import
android.content.Context
import
android.graphics.Color
import
android.graphics.drawable.ColorDrawable
import
android.view.LayoutInflater
import
com.base.s
mart
filemanager.R
import
com.base.s
mart
filemanager.databinding.DialogPermissonOpenBinding
import
com.base.s
uper
filemanager.R
import
com.base.s
uper
filemanager.databinding.DialogPermissonOpenBinding
import
com.blankj.utilcode.util.SpanUtils
object
DialogViews
{
...
...
app/src/main/java/com/base/s
mart
filemanager/view/FileDeleteDialog.kt
→
app/src/main/java/com/base/s
uper
filemanager/view/FileDeleteDialog.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.view
package
com.base.s
uper
filemanager.view
import
android.content.Context
import
android.text.SpannableString
...
...
@@ -8,8 +8,8 @@ import android.view.LayoutInflater
import
android.view.ViewGroup
import
androidx.appcompat.app.AlertDialog
import
androidx.core.content.ContextCompat
import
com.base.s
mart
filemanager.R
import
com.base.s
mart
filemanager.databinding.DialogFileDeleteBinding
import
com.base.s
uper
filemanager.R
import
com.base.s
uper
filemanager.databinding.DialogFileDeleteBinding
object
FileDeleteDialog
{
...
...
app/src/main/java/com/base/s
mart
filemanager/view/XmlEx.kt
→
app/src/main/java/com/base/s
uper
filemanager/view/XmlEx.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager.view
package
com.base.s
uper
filemanager.view
import
android.view.LayoutInflater
import
android.view.View
...
...
app/src/main/res/drawable-xxhdpi/qdylogo.png
0 → 100644
View file @
4a0909ac
44 KB
app/src/main/res/drawable/splash_bp.xml
View file @
4a0909ac
<?xml version="1.0" encoding="utf-8"?>
<layer-list
xmlns:android=
"http://schemas.android.com/apk/res/android"
>
<item
android:drawable=
"@color/white"
/>
<item
android:drawable=
"@drawable/splash_bg"
/
>
<item
android:drawable=
"@color/white"
/>
<!-- <item android:drawable="@drawable/splash_bg" />--
>
<item
android:top=
"130dp"
android:gravity=
"top|center_horizontal"
>
<bitmap
android:src=
"@mipmap/icon_text"
/>
android:gravity=
"top|center_horizontal"
android:top=
"130dp"
>
<bitmap
android:src=
"@drawable/qdylogo"
/>
</item>
</layer-list>
\ No newline at end of file
app/src/main/res/layout/activity_layout_web_privacy.xml
0 → 100644
View file @
4a0909ac
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:orientation=
"vertical"
>
<RelativeLayout
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"14dp"
>
<androidx.appcompat.widget.AppCompatImageView
android:id=
"@+id/id_back"
android:layout_width=
"45dp"
android:layout_height=
"45dp"
android:layout_centerVertical=
"true"
android:paddingHorizontal=
"12dp"
android:src=
"@drawable/fanhui"
android:tint=
"#333333"
/>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_centerInParent=
"true"
android:text=
"Privacy Policy"
android:textColor=
"#333333"
android:textSize=
"17sp"
android:textStyle=
"bold"
tools:ignore=
"HardcodedText"
/>
</RelativeLayout>
<WebView
android:id=
"@+id/id_web"
android:layout_width=
"match_parent"
android:layout_height=
"0dp"
android:layout_marginTop=
"14dp"
android:layout_weight=
"1"
android:padding=
"10dp"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/layout/activity_splash.xml
View file @
4a0909ac
...
...
@@ -3,9 +3,9 @@
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:id=
"@+id/main"
android:background=
"@drawable/splash_bp"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
android:background=
"@drawable/splash_bp"
android:orientation=
"vertical"
tools:context=
".activity.splash.SplashActivity"
>
...
...
@@ -26,7 +26,20 @@
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"49dp"
android:gravity=
"center_horizontal"
android:orientation=
"vertical"
>
android:orientation=
"vertical"
android:visibility=
"gone"
>
<TextView
android:id=
"@+id/tv_load"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"8dp"
android:text=
"Loading..."
android:textColor=
"#333333"
android:textSize=
"15sp"
tools:ignore=
"HardcodedText"
/>
<ProgressBar
android:id=
"@+id/pb"
...
...
@@ -37,17 +50,57 @@
android:progressDrawable=
"@drawable/shape_splash_s"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
<androidx.appcompat.widget.LinearLayoutCompat
android:id=
"@+id/id_ll_yinsi"
android:layout_width=
"match_parent"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"20dp"
android:gravity=
"center"
>
<TextView
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginHorizontal=
"4dp"
android:text=
"By continuing you are agreeing to the"
android:textColor=
"#676767"
android:textSize=
"14sp"
tools:ignore=
"HardcodedText"
/>
<TextView
android:id=
"@+id/tv_load"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginTop=
"18dp"
android:text=
"Loading..."
android:textColor=
"#000000"
android:textSize=
"15sp"
android:text=
" & "
android:visibility=
"gone"
tools:ignore=
"HardcodedText"
/>
<TextView
android:id=
"@+id/id_tv_privacy_policy"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:text=
"Privacy Policy"
android:textColor=
"#676767"
android:textSize=
"14sp"
tools:ignore=
"HardcodedText"
/>
</androidx.appcompat.widget.LinearLayoutCompat>
<com.noober.background.view.BLTextView
android:id=
"@+id/id_tv_start"
android:layout_width=
"match_parent"
android:layout_height=
"48dp"
android:layout_marginHorizontal=
"40dp"
android:layout_marginBottom=
"49dp"
android:gravity=
"center"
android:text=
"START TO USE"
android:textColor=
"@color/white"
android:textSize=
"18sp"
android:textStyle=
"bold"
android:visibility=
"visible"
app:bl_corners_radius=
"18dp"
app:bl_solid_color=
"#027CF6"
tools:ignore=
"HardcodedText"
/>
</LinearLayout>
\ No newline at end of file
app/src/main/res/values/strings.xml
View file @
4a0909ac
...
...
@@ -2,4 +2,5 @@
<!-- TODO: Remove or change this placeholder text -->
<string
name=
"hello_blank_fragment"
>
Hello blank fragment
</string>
<string
name=
"app_name"
>
Super File Manager
</string>
<string
name=
"facebook_app_id"
translatable=
"false"
>
486434960399485
</string>
</resources>
\ No newline at end of file
app/src/test/java/com/base/s
mart
filemanager/ExampleUnitTest.kt
→
app/src/test/java/com/base/s
uper
filemanager/ExampleUnitTest.kt
View file @
4a0909ac
package
com.base.s
mart
filemanager
package
com.base.s
uper
filemanager
import
org.junit.Test
...
...
settings.gradle
View file @
4a0909ac
...
...
@@ -24,5 +24,5 @@ dependencyResolutionManagement {
}
}
rootProject
.
name
=
"s
mart
-file-manager"
rootProject
.
name
=
"s
uper
-file-manager"
include
':app'
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment