@@ -140,7 +140,11 @@ public class AppListFragment extends Fragment implements AppListAdapter.OnAppTog
|
||||
RadioButton radioStandardInjection = dialogView.findViewById(R.id.radioStandardInjection);
|
||||
RadioButton radioRiruInjection = dialogView.findViewById(R.id.radioRiruInjection);
|
||||
RadioButton radioCustomLinkerInjection = dialogView.findViewById(R.id.radioCustomLinkerInjection);
|
||||
CheckBox checkboxEnableGadget = dialogView.findViewById(R.id.checkboxEnableGadget);
|
||||
RadioGroup gadgetConfigGroup = dialogView.findViewById(R.id.gadgetConfigGroup);
|
||||
RadioButton radioNoGadget = dialogView.findViewById(R.id.radioNoGadget);
|
||||
RadioButton radioUseGlobalGadget = dialogView.findViewById(R.id.radioUseGlobalGadget);
|
||||
RadioButton radioUseCustomGadget = dialogView.findViewById(R.id.radioUseCustomGadget);
|
||||
TextView tvGlobalGadgetInfo = dialogView.findViewById(R.id.tvGlobalGadgetInfo);
|
||||
com.google.android.material.button.MaterialButton btnConfigureGadget = dialogView.findViewById(R.id.btnConfigureGadget);
|
||||
|
||||
appIcon.setImageDrawable(appInfo.getAppIcon());
|
||||
@@ -158,30 +162,71 @@ public class AppListFragment extends Fragment implements AppListAdapter.OnAppTog
|
||||
}
|
||||
|
||||
// Load gadget config
|
||||
ConfigManager.GadgetConfig gadgetConfig = configManager.getAppGadgetConfig(appInfo.getPackageName());
|
||||
checkboxEnableGadget.setChecked(gadgetConfig != null);
|
||||
btnConfigureGadget.setEnabled(gadgetConfig != null);
|
||||
boolean useGlobalGadget = configManager.getAppUseGlobalGadget(appInfo.getPackageName());
|
||||
ConfigManager.GadgetConfig appSpecificGadget = configManager.getAppGadgetConfig(appInfo.getPackageName());
|
||||
ConfigManager.GadgetConfig globalGadget = configManager.getGlobalGadgetConfig();
|
||||
|
||||
// Setup gadget listeners
|
||||
checkboxEnableGadget.setOnCheckedChangeListener((buttonView, isChecked) -> {
|
||||
btnConfigureGadget.setEnabled(isChecked);
|
||||
if (!isChecked) {
|
||||
// Remove gadget config when unchecked
|
||||
// Update global gadget info
|
||||
if (globalGadget != null) {
|
||||
String info = "全局: " + globalGadget.gadgetName;
|
||||
if (globalGadget.mode.equals("server")) {
|
||||
info += " (端口: " + globalGadget.port + ")";
|
||||
}
|
||||
tvGlobalGadgetInfo.setText(info);
|
||||
} else {
|
||||
tvGlobalGadgetInfo.setText("未配置全局Gadget");
|
||||
}
|
||||
|
||||
// Set initial radio selection
|
||||
if (!useGlobalGadget && appSpecificGadget != null) {
|
||||
radioUseCustomGadget.setChecked(true);
|
||||
btnConfigureGadget.setVisibility(View.VISIBLE);
|
||||
btnConfigureGadget.setEnabled(true);
|
||||
} else if (useGlobalGadget && globalGadget != null) {
|
||||
radioUseGlobalGadget.setChecked(true);
|
||||
btnConfigureGadget.setVisibility(View.GONE);
|
||||
} else {
|
||||
radioNoGadget.setChecked(true);
|
||||
btnConfigureGadget.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
// Setup gadget radio group listener
|
||||
gadgetConfigGroup.setOnCheckedChangeListener((group, checkedId) -> {
|
||||
if (checkedId == R.id.radioNoGadget) {
|
||||
btnConfigureGadget.setVisibility(View.GONE);
|
||||
configManager.setAppUseGlobalGadget(appInfo.getPackageName(), false);
|
||||
configManager.setAppGadgetConfig(appInfo.getPackageName(), null);
|
||||
} else if (checkedId == R.id.radioUseGlobalGadget) {
|
||||
btnConfigureGadget.setVisibility(View.GONE);
|
||||
configManager.setAppUseGlobalGadget(appInfo.getPackageName(), true);
|
||||
configManager.setAppGadgetConfig(appInfo.getPackageName(), null);
|
||||
} else if (checkedId == R.id.radioUseCustomGadget) {
|
||||
btnConfigureGadget.setVisibility(View.VISIBLE);
|
||||
btnConfigureGadget.setEnabled(true);
|
||||
configManager.setAppUseGlobalGadget(appInfo.getPackageName(), false);
|
||||
}
|
||||
});
|
||||
|
||||
// Configure button listener
|
||||
btnConfigureGadget.setOnClickListener(v -> {
|
||||
ConfigManager.GadgetConfig currentConfig = configManager.getAppGadgetConfig(appInfo.getPackageName());
|
||||
ConfigManager.GadgetConfig currentConfig = null;
|
||||
if (!useGlobalGadget) {
|
||||
currentConfig = configManager.getAppGadgetConfig(appInfo.getPackageName());
|
||||
}
|
||||
if (currentConfig == null) {
|
||||
currentConfig = new ConfigManager.GadgetConfig();
|
||||
}
|
||||
|
||||
GadgetConfigDialog gadgetDialog = GadgetConfigDialog.newInstance(currentConfig);
|
||||
gadgetDialog.setOnGadgetConfigListener(config -> {
|
||||
configManager.setAppGadgetConfig(appInfo.getPackageName(), config);
|
||||
});
|
||||
gadgetDialog.show(getParentFragmentManager(), "gadget_config");
|
||||
GadgetConfigDialog dialog = new GadgetConfigDialog(
|
||||
getContext(),
|
||||
"配置" + appInfo.getAppName() + "的Gadget",
|
||||
currentConfig,
|
||||
config -> {
|
||||
configManager.setAppUseGlobalGadget(appInfo.getPackageName(), false);
|
||||
configManager.setAppGadgetConfig(appInfo.getPackageName(), config);
|
||||
}
|
||||
);
|
||||
dialog.show();
|
||||
});
|
||||
|
||||
// Setup SO list
|
||||
@@ -216,16 +261,6 @@ public class AppListFragment extends Fragment implements AppListAdapter.OnAppTog
|
||||
}
|
||||
configManager.setAppInjectionMethod(appInfo.getPackageName(), selectedMethod);
|
||||
|
||||
// Save gadget config if enabled
|
||||
if (checkboxEnableGadget.isChecked()) {
|
||||
ConfigManager.GadgetConfig currentGadgetConfig = configManager.getAppGadgetConfig(appInfo.getPackageName());
|
||||
if (currentGadgetConfig == null) {
|
||||
// Create default config if not already configured
|
||||
currentGadgetConfig = new ConfigManager.GadgetConfig();
|
||||
configManager.setAppGadgetConfig(appInfo.getPackageName(), currentGadgetConfig);
|
||||
}
|
||||
}
|
||||
|
||||
// Save SO selection
|
||||
if (soListRecyclerView.getAdapter() != null) {
|
||||
SoSelectionAdapter adapter = (SoSelectionAdapter) soListRecyclerView.getAdapter();
|
||||
|
||||
@@ -265,11 +265,46 @@ public class ConfigManager {
|
||||
public GadgetConfig getAppGadgetConfig(String packageName) {
|
||||
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||
if (appConfig == null) {
|
||||
return null;
|
||||
// If no app config, return global gadget config
|
||||
return config.globalGadgetConfig;
|
||||
}
|
||||
|
||||
// If app is set to use global gadget, return global config
|
||||
if (appConfig.useGlobalGadget) {
|
||||
return config.globalGadgetConfig;
|
||||
}
|
||||
|
||||
// Otherwise return app-specific gadget config
|
||||
return appConfig.gadgetConfig;
|
||||
}
|
||||
|
||||
public GadgetConfig getGlobalGadgetConfig() {
|
||||
return config.globalGadgetConfig;
|
||||
}
|
||||
|
||||
public void setGlobalGadgetConfig(GadgetConfig gadgetConfig) {
|
||||
config.globalGadgetConfig = gadgetConfig;
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
public boolean getAppUseGlobalGadget(String packageName) {
|
||||
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||
if (appConfig == null) {
|
||||
return true; // Default to use global
|
||||
}
|
||||
return appConfig.useGlobalGadget;
|
||||
}
|
||||
|
||||
public void setAppUseGlobalGadget(String packageName, boolean useGlobal) {
|
||||
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||
if (appConfig == null) {
|
||||
appConfig = new AppConfig();
|
||||
config.perAppConfig.put(packageName, appConfig);
|
||||
}
|
||||
appConfig.useGlobalGadget = useGlobal;
|
||||
saveConfig();
|
||||
}
|
||||
|
||||
public void setAppGadgetConfig(String packageName, GadgetConfig gadgetConfig) {
|
||||
AppConfig appConfig = config.perAppConfig.get(packageName);
|
||||
if (appConfig == null) {
|
||||
@@ -478,8 +513,9 @@ public class ConfigManager {
|
||||
Log.i(TAG, "Deployment complete for: " + packageName);
|
||||
|
||||
// Deploy gadget config if configured
|
||||
if (appConfig.gadgetConfig != null) {
|
||||
deployGadgetConfigFile(packageName, appConfig.gadgetConfig);
|
||||
ConfigManager.GadgetConfig gadgetToUse = getAppGadgetConfig(packageName);
|
||||
if (gadgetToUse != null) {
|
||||
deployGadgetConfigFile(packageName, gadgetToUse);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -527,8 +563,9 @@ public class ConfigManager {
|
||||
}
|
||||
|
||||
// Clean up gadget config file if exists
|
||||
if (appConfig.gadgetConfig != null) {
|
||||
String gadgetConfigName = appConfig.gadgetConfig.gadgetName.replace(".so", ".config.so");
|
||||
ConfigManager.GadgetConfig gadgetToUse = getAppGadgetConfig(packageName);
|
||||
if (gadgetToUse != null) {
|
||||
String gadgetConfigName = gadgetToUse.gadgetName.replace(".so", ".config.so");
|
||||
String configPath = filesDir + "/" + gadgetConfigName;
|
||||
|
||||
Shell.Result checkConfigResult = Shell.cmd("test -f \"" + configPath + "\" && echo 'exists'").exec();
|
||||
@@ -562,6 +599,7 @@ public class ConfigManager {
|
||||
public int injectionDelay = 2; // Default 2 seconds
|
||||
public List<SoFile> globalSoFiles = new ArrayList<>();
|
||||
public Map<String, AppConfig> perAppConfig = new HashMap<>();
|
||||
public GadgetConfig globalGadgetConfig = null; // Global gadget configuration
|
||||
}
|
||||
|
||||
public static class AppConfig {
|
||||
@@ -569,6 +607,7 @@ public class ConfigManager {
|
||||
public List<SoFile> soFiles = new ArrayList<>();
|
||||
public String injectionMethod = "standard"; // "standard", "riru" or "custom_linker"
|
||||
public GadgetConfig gadgetConfig = null;
|
||||
public boolean useGlobalGadget = true; // Whether to use global gadget settings
|
||||
}
|
||||
|
||||
public static class SoFile {
|
||||
|
||||
@@ -57,6 +57,7 @@ public class GadgetConfigDialog extends DialogFragment {
|
||||
// Configuration data
|
||||
private ConfigManager.GadgetConfig config;
|
||||
private OnGadgetConfigListener listener;
|
||||
private String customTitle;
|
||||
|
||||
// Flag to prevent recursive updates
|
||||
private boolean isUpdatingUI = false;
|
||||
@@ -75,6 +76,21 @@ public class GadgetConfigDialog extends DialogFragment {
|
||||
return dialog;
|
||||
}
|
||||
|
||||
// Constructor for non-fragment usage
|
||||
public GadgetConfigDialog(Context context, String title, ConfigManager.GadgetConfig config, OnGadgetConfigListener listener) {
|
||||
// This constructor is for compatibility with direct dialog creation
|
||||
// The actual dialog will be created in show() method
|
||||
this.savedContext = context;
|
||||
this.customTitle = title;
|
||||
this.config = config != null ? config : new ConfigManager.GadgetConfig();
|
||||
this.listener = listener;
|
||||
}
|
||||
|
||||
// Default constructor required for DialogFragment
|
||||
public GadgetConfigDialog() {
|
||||
// Empty constructor required
|
||||
}
|
||||
|
||||
public void setOnGadgetConfigListener(OnGadgetConfigListener listener) {
|
||||
this.listener = listener;
|
||||
}
|
||||
@@ -129,8 +145,10 @@ public class GadgetConfigDialog extends DialogFragment {
|
||||
setupListeners();
|
||||
updateJsonPreview();
|
||||
|
||||
String title = customTitle != null ? customTitle : "Gadget 配置";
|
||||
|
||||
return new MaterialAlertDialogBuilder(getContext())
|
||||
.setTitle("Gadget 配置")
|
||||
.setTitle(title)
|
||||
.setView(view)
|
||||
.setPositiveButton("保存", (dialog, which) -> saveConfig())
|
||||
.setNegativeButton("取消", null)
|
||||
@@ -567,6 +585,50 @@ public class GadgetConfigDialog extends DialogFragment {
|
||||
.show();
|
||||
}
|
||||
|
||||
// Show method for non-fragment usage
|
||||
public void show() {
|
||||
if (getContext() == null) {
|
||||
throw new IllegalStateException("Context is required for non-fragment usage");
|
||||
}
|
||||
|
||||
View view = LayoutInflater.from(getContext()).inflate(R.layout.dialog_gadget_config, null);
|
||||
initViews(view);
|
||||
|
||||
// Initialize config if null
|
||||
if (config == null) {
|
||||
config = new ConfigManager.GadgetConfig();
|
||||
}
|
||||
|
||||
loadConfig();
|
||||
setupListeners();
|
||||
updateJsonPreview();
|
||||
|
||||
String title = customTitle != null ? customTitle : "Gadget 配置";
|
||||
|
||||
new MaterialAlertDialogBuilder(getContext())
|
||||
.setTitle(title)
|
||||
.setView(view)
|
||||
.setPositiveButton("保存", (dialog, which) -> saveConfig())
|
||||
.setNegativeButton("取消", null)
|
||||
.show();
|
||||
}
|
||||
|
||||
private Context savedContext;
|
||||
|
||||
@Override
|
||||
public Context getContext() {
|
||||
Context context = super.getContext();
|
||||
if (context == null) {
|
||||
return savedContext;
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
// Constructor for non-fragment usage needs to save context
|
||||
public void setContext(Context context) {
|
||||
this.savedContext = context;
|
||||
}
|
||||
|
||||
private String getPathFromUri(Uri uri) {
|
||||
String path = null;
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ import android.widget.RadioGroup;
|
||||
import android.widget.EditText;
|
||||
import android.text.TextWatcher;
|
||||
import android.text.Editable;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Button;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
@@ -28,6 +30,8 @@ public class SettingsFragment extends Fragment {
|
||||
private RadioButton radioShowAll;
|
||||
private RadioButton radioHideSystem;
|
||||
private EditText editInjectionDelay;
|
||||
private TextView tvGlobalGadgetStatus;
|
||||
private Button btnConfigureGlobalGadget;
|
||||
private ConfigManager configManager;
|
||||
|
||||
private SharedPreferences sharedPreferences;
|
||||
@@ -59,6 +63,8 @@ public class SettingsFragment extends Fragment {
|
||||
radioShowAll = view.findViewById(R.id.radio_show_all);
|
||||
radioHideSystem = view.findViewById(R.id.radio_hide_system);
|
||||
editInjectionDelay = view.findViewById(R.id.editInjectionDelay);
|
||||
tvGlobalGadgetStatus = view.findViewById(R.id.tvGlobalGadgetStatus);
|
||||
btnConfigureGlobalGadget = view.findViewById(R.id.btnConfigureGlobalGadget);
|
||||
|
||||
configManager = new ConfigManager(getContext());
|
||||
}
|
||||
@@ -79,6 +85,9 @@ public class SettingsFragment extends Fragment {
|
||||
// Load injection delay
|
||||
int injectionDelay = configManager.getInjectionDelay();
|
||||
editInjectionDelay.setText(String.valueOf(injectionDelay));
|
||||
|
||||
// Load global gadget status
|
||||
updateGlobalGadgetStatus();
|
||||
}
|
||||
|
||||
private void setupListeners() {
|
||||
@@ -124,6 +133,11 @@ public class SettingsFragment extends Fragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Global gadget configuration button
|
||||
btnConfigureGlobalGadget.setOnClickListener(v -> {
|
||||
showGlobalGadgetConfigDialog();
|
||||
});
|
||||
}
|
||||
|
||||
public void setOnSettingsChangeListener(OnSettingsChangeListener listener) {
|
||||
@@ -133,4 +147,34 @@ public class SettingsFragment extends Fragment {
|
||||
public boolean isHideSystemApps() {
|
||||
return sharedPreferences.getBoolean(KEY_HIDE_SYSTEM_APPS, false);
|
||||
}
|
||||
|
||||
private void updateGlobalGadgetStatus() {
|
||||
ConfigManager.GadgetConfig globalGadget = configManager.getGlobalGadgetConfig();
|
||||
if (globalGadget != null) {
|
||||
String status = "已配置: " + globalGadget.gadgetName;
|
||||
if (globalGadget.mode.equals("server")) {
|
||||
status += " (Server模式, 端口: " + globalGadget.port + ")";
|
||||
} else {
|
||||
status += " (Script模式)";
|
||||
}
|
||||
tvGlobalGadgetStatus.setText(status);
|
||||
} else {
|
||||
tvGlobalGadgetStatus.setText("未配置");
|
||||
}
|
||||
}
|
||||
|
||||
private void showGlobalGadgetConfigDialog() {
|
||||
// Use existing GadgetConfigDialog
|
||||
GadgetConfigDialog dialog = new GadgetConfigDialog(
|
||||
getContext(),
|
||||
"全局Gadget配置",
|
||||
configManager.getGlobalGadgetConfig(),
|
||||
gadgetConfig -> {
|
||||
// Save global gadget configuration
|
||||
configManager.setGlobalGadgetConfig(gadgetConfig);
|
||||
updateGlobalGadgetStatus();
|
||||
}
|
||||
);
|
||||
dialog.show();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -88,35 +88,67 @@
|
||||
android:layout_marginTop="16dp"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
<LinearLayout
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Gadget 配置"
|
||||
android:textSize="14sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/gadgetConfigGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal"
|
||||
android:gravity="center_vertical"
|
||||
android:orientation="vertical"
|
||||
android:layout_marginBottom="8dp">
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/checkboxEnableGadget"
|
||||
<RadioButton
|
||||
android:id="@+id/radioNoGadget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="不使用Gadget"
|
||||
android:checked="true" />
|
||||
|
||||
<RadioButton
|
||||
android:id="@+id/radioUseGlobalGadget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="使用全局Gadget配置" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvGlobalGadgetInfo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="启用 Gadget 配置"
|
||||
android:layout_marginEnd="8dp" />
|
||||
android:layout_marginStart="32dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:text="未配置全局Gadget"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:textSize="12sp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnConfigureGadget"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="36dp"
|
||||
android:text="配置"
|
||||
android:textSize="12sp"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:enabled="false" />
|
||||
<RadioButton
|
||||
android:id="@+id/radioUseCustomGadget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="自定义Gadget配置" />
|
||||
|
||||
</LinearLayout>
|
||||
</RadioGroup>
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnConfigureGadget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="配置Gadget"
|
||||
android:textSize="14sp"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton"
|
||||
android:enabled="false"
|
||||
android:visibility="gone"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="Gadget可用于Frida调试,勾选后可配置监听地址和端口"
|
||||
android:text="Gadget可用于Frida调试,可配置监听地址和端口"
|
||||
android:textSize="12sp"
|
||||
android:textColor="?android:attr/textColorSecondary"
|
||||
android:layout_marginBottom="16dp" />
|
||||
|
||||
@@ -143,6 +143,53 @@
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- 全局Gadget配置 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="16dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:padding="16dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="全局Gadget配置"
|
||||
android:textSize="16sp"
|
||||
android:textStyle="bold"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="配置全局默认的Gadget设置,应用可以选择使用或覆盖"
|
||||
android:textSize="14sp"
|
||||
android:textColor="@android:color/darker_gray"
|
||||
android:layout_marginBottom="12dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/tvGlobalGadgetStatus"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="未配置"
|
||||
android:textSize="14sp"
|
||||
android:layout_marginBottom="8dp" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/btnConfigureGlobalGadget"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="配置全局Gadget"
|
||||
style="@style/Widget.MaterialComponents.Button.OutlinedButton" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
<!-- 其他设置可以在这里添加 -->
|
||||
<com.google.android.material.card.MaterialCardView
|
||||
android:layout_width="match_parent"
|
||||
|
||||
@@ -17,8 +17,8 @@ set(SOURCES
|
||||
|
||||
find_library(log-lib log)
|
||||
|
||||
# Build as shared library
|
||||
add_library(mylinker SHARED ${SOURCES})
|
||||
# Build as static library to be linked into main module
|
||||
add_library(mylinker STATIC ${SOURCES})
|
||||
|
||||
target_link_libraries(mylinker ${log-lib})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user